speckeeper 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,11 +1,12 @@
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
+ import { isOptionActive, derivePolicy } from 'cli-contracts/policy';
7
8
  import chalk4 from 'chalk';
8
- import { parse } from 'yaml';
9
+ import { stringify, parse } from 'yaml';
9
10
  import 'crypto';
10
11
  import { glob } from 'glob';
11
12
  import nodeSqlParser from 'node-sql-parser';
@@ -535,6 +536,1108 @@ var init_dsl = __esm({
535
536
  init_workflows();
536
537
  }
537
538
  });
539
+ var commandDefinitions = {
540
+ "init": {
541
+ "effects": {
542
+ "riskLevel": "medium",
543
+ "writes": [
544
+ {
545
+ "target": "speckeeper.config.ts, design/ directory",
546
+ "description": "generates config and starter template files",
547
+ "idempotent": false
548
+ }
549
+ ]
550
+ },
551
+ "options": [
552
+ {
553
+ "name": "force",
554
+ "schema": {
555
+ "type": "boolean",
556
+ "default": false
557
+ },
558
+ "effects": {
559
+ "riskLevel": "high",
560
+ "writes": [
561
+ {
562
+ "target": "existing project files",
563
+ "description": "overwrites existing config and design files",
564
+ "overwrite": true,
565
+ "destructive": true
566
+ }
567
+ ]
568
+ }
569
+ },
570
+ {
571
+ "name": "format",
572
+ "schema": {
573
+ "type": "string",
574
+ "default": "ts",
575
+ "enum": [
576
+ "ts",
577
+ "yaml"
578
+ ]
579
+ }
580
+ }
581
+ ],
582
+ "env": {
583
+ "CURSOR_API_KEY": {
584
+ "sensitive": true
585
+ },
586
+ "GEMINI_API_KEY": {
587
+ "sensitive": true
588
+ },
589
+ "OPENAI_API_KEY": {
590
+ "sensitive": true
591
+ },
592
+ "ANTHROPIC_API_KEY": {
593
+ "sensitive": true
594
+ }
595
+ }
596
+ },
597
+ "build": {
598
+ "effects": {
599
+ "riskLevel": "low",
600
+ "writes": [
601
+ {
602
+ "target": "docs/ directory",
603
+ "description": "generated Markdown documentation files",
604
+ "overwrite": true,
605
+ "idempotent": true
606
+ }
607
+ ]
608
+ },
609
+ "options": [
610
+ {
611
+ "name": "config",
612
+ "schema": {
613
+ "type": "string"
614
+ },
615
+ "file": {
616
+ "mode": "read",
617
+ "exists": true,
618
+ "encoding": "utf-8"
619
+ }
620
+ },
621
+ {
622
+ "name": "output",
623
+ "schema": {
624
+ "type": "string",
625
+ "default": "."
626
+ }
627
+ },
628
+ {
629
+ "name": "format",
630
+ "schema": {
631
+ "type": "string",
632
+ "default": "both",
633
+ "enum": [
634
+ "markdown",
635
+ "json",
636
+ "both"
637
+ ]
638
+ }
639
+ },
640
+ {
641
+ "name": "watch",
642
+ "schema": {
643
+ "type": "boolean",
644
+ "default": false
645
+ },
646
+ "effects": {
647
+ "executionMode": "watch"
648
+ }
649
+ },
650
+ {
651
+ "name": "verbose",
652
+ "schema": {
653
+ "type": "boolean",
654
+ "default": false
655
+ }
656
+ }
657
+ ],
658
+ "env": {
659
+ "CURSOR_API_KEY": {
660
+ "sensitive": true
661
+ },
662
+ "GEMINI_API_KEY": {
663
+ "sensitive": true
664
+ },
665
+ "OPENAI_API_KEY": {
666
+ "sensitive": true
667
+ },
668
+ "ANTHROPIC_API_KEY": {
669
+ "sensitive": true
670
+ }
671
+ }
672
+ },
673
+ "lint": {
674
+ "options": [
675
+ {
676
+ "name": "config",
677
+ "schema": {
678
+ "type": "string"
679
+ },
680
+ "file": {
681
+ "mode": "read",
682
+ "exists": true,
683
+ "encoding": "utf-8"
684
+ }
685
+ },
686
+ {
687
+ "name": "phase",
688
+ "schema": {
689
+ "type": "string",
690
+ "enum": [
691
+ "REQ",
692
+ "HLD",
693
+ "LLD",
694
+ "OPS"
695
+ ]
696
+ }
697
+ },
698
+ {
699
+ "name": "strict",
700
+ "schema": {
701
+ "type": "boolean",
702
+ "default": false
703
+ }
704
+ },
705
+ {
706
+ "name": "fix",
707
+ "schema": {
708
+ "type": "boolean",
709
+ "default": false
710
+ }
711
+ },
712
+ {
713
+ "name": "format",
714
+ "schema": {
715
+ "type": "string",
716
+ "default": "text",
717
+ "enum": [
718
+ "text",
719
+ "json",
720
+ "github"
721
+ ]
722
+ }
723
+ }
724
+ ],
725
+ "env": {
726
+ "CURSOR_API_KEY": {
727
+ "sensitive": true
728
+ },
729
+ "GEMINI_API_KEY": {
730
+ "sensitive": true
731
+ },
732
+ "OPENAI_API_KEY": {
733
+ "sensitive": true
734
+ },
735
+ "ANTHROPIC_API_KEY": {
736
+ "sensitive": true
737
+ }
738
+ }
739
+ },
740
+ "drift": {
741
+ "options": [
742
+ {
743
+ "name": "config",
744
+ "schema": {
745
+ "type": "string"
746
+ },
747
+ "file": {
748
+ "mode": "read",
749
+ "exists": true,
750
+ "encoding": "utf-8"
751
+ }
752
+ },
753
+ {
754
+ "name": "update",
755
+ "schema": {
756
+ "type": "boolean",
757
+ "default": false
758
+ }
759
+ },
760
+ {
761
+ "name": "format",
762
+ "schema": {
763
+ "type": "string",
764
+ "default": "text",
765
+ "enum": [
766
+ "text",
767
+ "json",
768
+ "diff"
769
+ ]
770
+ }
771
+ },
772
+ {
773
+ "name": "fail-on-drift",
774
+ "schema": {
775
+ "type": "boolean",
776
+ "default": false
777
+ }
778
+ }
779
+ ],
780
+ "env": {
781
+ "CURSOR_API_KEY": {
782
+ "sensitive": true
783
+ },
784
+ "GEMINI_API_KEY": {
785
+ "sensitive": true
786
+ },
787
+ "OPENAI_API_KEY": {
788
+ "sensitive": true
789
+ },
790
+ "ANTHROPIC_API_KEY": {
791
+ "sensitive": true
792
+ }
793
+ }
794
+ },
795
+ "check": {
796
+ "options": [
797
+ {
798
+ "name": "config",
799
+ "schema": {
800
+ "type": "string"
801
+ },
802
+ "file": {
803
+ "mode": "read",
804
+ "exists": true,
805
+ "encoding": "utf-8"
806
+ }
807
+ },
808
+ {
809
+ "name": "strict",
810
+ "schema": {
811
+ "type": "boolean",
812
+ "default": false
813
+ }
814
+ },
815
+ {
816
+ "name": "verbose",
817
+ "schema": {
818
+ "type": "boolean",
819
+ "default": false
820
+ }
821
+ },
822
+ {
823
+ "name": "coverage",
824
+ "schema": {
825
+ "type": "boolean",
826
+ "default": false
827
+ }
828
+ }
829
+ ],
830
+ "env": {
831
+ "CURSOR_API_KEY": {
832
+ "sensitive": true
833
+ },
834
+ "GEMINI_API_KEY": {
835
+ "sensitive": true
836
+ },
837
+ "OPENAI_API_KEY": {
838
+ "sensitive": true
839
+ },
840
+ "ANTHROPIC_API_KEY": {
841
+ "sensitive": true
842
+ }
843
+ }
844
+ },
845
+ "new": {
846
+ "effects": {
847
+ "riskLevel": "low",
848
+ "writes": [
849
+ {
850
+ "target": "design/ directory",
851
+ "description": "new TypeScript spec file with auto-generated ID",
852
+ "idempotent": false
853
+ }
854
+ ]
855
+ },
856
+ "options": [
857
+ {
858
+ "name": "kind",
859
+ "schema": {
860
+ "type": "string"
861
+ }
862
+ },
863
+ {
864
+ "name": "name",
865
+ "schema": {
866
+ "type": "string"
867
+ }
868
+ },
869
+ {
870
+ "name": "output",
871
+ "schema": {
872
+ "type": "string"
873
+ }
874
+ },
875
+ {
876
+ "name": "template",
877
+ "schema": {
878
+ "type": "string"
879
+ },
880
+ "file": {
881
+ "mode": "read",
882
+ "exists": true,
883
+ "encoding": "utf-8"
884
+ }
885
+ },
886
+ {
887
+ "name": "dry-run",
888
+ "schema": {
889
+ "type": "boolean",
890
+ "default": false
891
+ }
892
+ }
893
+ ],
894
+ "env": {
895
+ "CURSOR_API_KEY": {
896
+ "sensitive": true
897
+ },
898
+ "GEMINI_API_KEY": {
899
+ "sensitive": true
900
+ },
901
+ "OPENAI_API_KEY": {
902
+ "sensitive": true
903
+ },
904
+ "ANTHROPIC_API_KEY": {
905
+ "sensitive": true
906
+ }
907
+ }
908
+ },
909
+ "impact": {
910
+ "options": [
911
+ {
912
+ "name": "config",
913
+ "schema": {
914
+ "type": "string"
915
+ },
916
+ "file": {
917
+ "mode": "read",
918
+ "exists": true,
919
+ "encoding": "utf-8"
920
+ }
921
+ },
922
+ {
923
+ "name": "depth",
924
+ "schema": {
925
+ "type": "integer",
926
+ "minimum": 1,
927
+ "default": 3
928
+ }
929
+ },
930
+ {
931
+ "name": "direction",
932
+ "schema": {
933
+ "type": "string",
934
+ "default": "both",
935
+ "enum": [
936
+ "upstream",
937
+ "downstream",
938
+ "both"
939
+ ]
940
+ }
941
+ },
942
+ {
943
+ "name": "format",
944
+ "schema": {
945
+ "type": "string",
946
+ "default": "text",
947
+ "enum": [
948
+ "text",
949
+ "json",
950
+ "mermaid"
951
+ ]
952
+ }
953
+ }
954
+ ],
955
+ "env": {
956
+ "CURSOR_API_KEY": {
957
+ "sensitive": true
958
+ },
959
+ "GEMINI_API_KEY": {
960
+ "sensitive": true
961
+ },
962
+ "OPENAI_API_KEY": {
963
+ "sensitive": true
964
+ },
965
+ "ANTHROPIC_API_KEY": {
966
+ "sensitive": true
967
+ }
968
+ }
969
+ },
970
+ "scaffold": {
971
+ "effects": {
972
+ "riskLevel": "low",
973
+ "writes": [
974
+ {
975
+ "target": "design/ directory",
976
+ "description": "generated _models/ and spec data files",
977
+ "idempotent": false
978
+ }
979
+ ]
980
+ },
981
+ "options": [
982
+ {
983
+ "name": "source",
984
+ "schema": {
985
+ "type": "string"
986
+ },
987
+ "file": {
988
+ "mode": "read",
989
+ "exists": true,
990
+ "encoding": "utf-8"
991
+ }
992
+ },
993
+ {
994
+ "name": "output",
995
+ "schema": {
996
+ "type": "string",
997
+ "default": "design/"
998
+ }
999
+ },
1000
+ {
1001
+ "name": "force",
1002
+ "schema": {
1003
+ "type": "boolean",
1004
+ "default": false
1005
+ },
1006
+ "effects": {
1007
+ "riskLevel": "medium",
1008
+ "writes": [
1009
+ {
1010
+ "target": "existing model and spec files",
1011
+ "description": "overwrites existing TypeScript model source files",
1012
+ "overwrite": true
1013
+ }
1014
+ ]
1015
+ }
1016
+ },
1017
+ {
1018
+ "name": "dry-run",
1019
+ "schema": {
1020
+ "type": "boolean",
1021
+ "default": false
1022
+ }
1023
+ },
1024
+ {
1025
+ "name": "format",
1026
+ "schema": {
1027
+ "type": "string",
1028
+ "default": "ts",
1029
+ "enum": [
1030
+ "ts",
1031
+ "yaml"
1032
+ ]
1033
+ }
1034
+ }
1035
+ ],
1036
+ "env": {
1037
+ "CURSOR_API_KEY": {
1038
+ "sensitive": true
1039
+ },
1040
+ "GEMINI_API_KEY": {
1041
+ "sensitive": true
1042
+ },
1043
+ "OPENAI_API_KEY": {
1044
+ "sensitive": true
1045
+ },
1046
+ "ANTHROPIC_API_KEY": {
1047
+ "sensitive": true
1048
+ }
1049
+ }
1050
+ },
1051
+ "convert": {
1052
+ "effects": {
1053
+ "riskLevel": "low",
1054
+ "writes": [
1055
+ {
1056
+ "target": ".yaml output file",
1057
+ "description": "YAML conversion of the TS spec data",
1058
+ "idempotent": true
1059
+ }
1060
+ ]
1061
+ },
1062
+ "options": [
1063
+ {
1064
+ "name": "output",
1065
+ "schema": {
1066
+ "type": "string"
1067
+ },
1068
+ "file": {
1069
+ "mode": "write",
1070
+ "encoding": "utf-8"
1071
+ }
1072
+ },
1073
+ {
1074
+ "name": "dry-run",
1075
+ "schema": {
1076
+ "type": "boolean",
1077
+ "default": false
1078
+ }
1079
+ }
1080
+ ],
1081
+ "env": {
1082
+ "CURSOR_API_KEY": {
1083
+ "sensitive": true
1084
+ },
1085
+ "GEMINI_API_KEY": {
1086
+ "sensitive": true
1087
+ },
1088
+ "OPENAI_API_KEY": {
1089
+ "sensitive": true
1090
+ },
1091
+ "ANTHROPIC_API_KEY": {
1092
+ "sensitive": true
1093
+ }
1094
+ }
1095
+ },
1096
+ "audit-requirements": {
1097
+ "effects": {
1098
+ "network": {
1099
+ "description": "LLM API calls to configured provider",
1100
+ "idempotent": true
1101
+ }
1102
+ },
1103
+ "options": [
1104
+ {
1105
+ "name": "config",
1106
+ "schema": {
1107
+ "type": "string"
1108
+ },
1109
+ "file": {
1110
+ "mode": "read",
1111
+ "exists": true,
1112
+ "encoding": "utf-8"
1113
+ }
1114
+ },
1115
+ {
1116
+ "name": "adapter",
1117
+ "schema": {
1118
+ "type": "string",
1119
+ "enum": [
1120
+ "cursor",
1121
+ "claude",
1122
+ "openai",
1123
+ "gemini",
1124
+ "mock"
1125
+ ]
1126
+ }
1127
+ },
1128
+ {
1129
+ "name": "model",
1130
+ "schema": {
1131
+ "type": "string"
1132
+ }
1133
+ },
1134
+ {
1135
+ "name": "dry-run",
1136
+ "schema": {
1137
+ "type": "boolean",
1138
+ "default": false
1139
+ }
1140
+ },
1141
+ {
1142
+ "name": "show-prompt",
1143
+ "schema": {
1144
+ "type": "boolean",
1145
+ "default": false
1146
+ }
1147
+ },
1148
+ {
1149
+ "name": "fail-on",
1150
+ "schema": {
1151
+ "type": "string",
1152
+ "enum": [
1153
+ "warning",
1154
+ "error",
1155
+ "critical"
1156
+ ],
1157
+ "default": "error"
1158
+ }
1159
+ },
1160
+ {
1161
+ "name": "output",
1162
+ "schema": {
1163
+ "type": "string"
1164
+ },
1165
+ "file": {
1166
+ "mode": "write",
1167
+ "encoding": "utf-8"
1168
+ }
1169
+ },
1170
+ {
1171
+ "name": "report-format",
1172
+ "schema": {
1173
+ "type": "string",
1174
+ "enum": [
1175
+ "json",
1176
+ "text",
1177
+ "yaml"
1178
+ ],
1179
+ "default": "json"
1180
+ }
1181
+ }
1182
+ ],
1183
+ "env": {
1184
+ "CURSOR_API_KEY": {
1185
+ "sensitive": true
1186
+ },
1187
+ "GEMINI_API_KEY": {
1188
+ "sensitive": true
1189
+ },
1190
+ "OPENAI_API_KEY": {
1191
+ "sensitive": true
1192
+ },
1193
+ "ANTHROPIC_API_KEY": {
1194
+ "sensitive": true
1195
+ }
1196
+ }
1197
+ },
1198
+ "propose-trace-links": {
1199
+ "effects": {
1200
+ "network": {
1201
+ "description": "LLM API calls to configured provider",
1202
+ "idempotent": true
1203
+ }
1204
+ },
1205
+ "options": [
1206
+ {
1207
+ "name": "config",
1208
+ "schema": {
1209
+ "type": "string"
1210
+ },
1211
+ "file": {
1212
+ "mode": "read",
1213
+ "exists": true,
1214
+ "encoding": "utf-8"
1215
+ }
1216
+ },
1217
+ {
1218
+ "name": "adapter",
1219
+ "schema": {
1220
+ "type": "string",
1221
+ "enum": [
1222
+ "cursor",
1223
+ "claude",
1224
+ "openai",
1225
+ "gemini",
1226
+ "mock"
1227
+ ]
1228
+ }
1229
+ },
1230
+ {
1231
+ "name": "model",
1232
+ "schema": {
1233
+ "type": "string"
1234
+ }
1235
+ },
1236
+ {
1237
+ "name": "dry-run",
1238
+ "schema": {
1239
+ "type": "boolean",
1240
+ "default": false
1241
+ }
1242
+ },
1243
+ {
1244
+ "name": "show-prompt",
1245
+ "schema": {
1246
+ "type": "boolean",
1247
+ "default": false
1248
+ }
1249
+ },
1250
+ {
1251
+ "name": "fail-on",
1252
+ "schema": {
1253
+ "type": "string",
1254
+ "enum": [
1255
+ "warning",
1256
+ "error",
1257
+ "critical"
1258
+ ],
1259
+ "default": "error"
1260
+ }
1261
+ },
1262
+ {
1263
+ "name": "output",
1264
+ "schema": {
1265
+ "type": "string"
1266
+ },
1267
+ "file": {
1268
+ "mode": "write",
1269
+ "encoding": "utf-8"
1270
+ }
1271
+ },
1272
+ {
1273
+ "name": "report-format",
1274
+ "schema": {
1275
+ "type": "string",
1276
+ "enum": [
1277
+ "json",
1278
+ "text",
1279
+ "yaml"
1280
+ ],
1281
+ "default": "json"
1282
+ }
1283
+ }
1284
+ ],
1285
+ "env": {
1286
+ "CURSOR_API_KEY": {
1287
+ "sensitive": true
1288
+ },
1289
+ "GEMINI_API_KEY": {
1290
+ "sensitive": true
1291
+ },
1292
+ "OPENAI_API_KEY": {
1293
+ "sensitive": true
1294
+ },
1295
+ "ANTHROPIC_API_KEY": {
1296
+ "sensitive": true
1297
+ }
1298
+ }
1299
+ },
1300
+ "explain-impact": {
1301
+ "effects": {
1302
+ "network": {
1303
+ "description": "LLM API calls to configured provider",
1304
+ "idempotent": true
1305
+ }
1306
+ },
1307
+ "options": [
1308
+ {
1309
+ "name": "adapter",
1310
+ "schema": {
1311
+ "type": "string",
1312
+ "enum": [
1313
+ "cursor",
1314
+ "claude",
1315
+ "openai",
1316
+ "gemini",
1317
+ "mock"
1318
+ ]
1319
+ }
1320
+ },
1321
+ {
1322
+ "name": "model",
1323
+ "schema": {
1324
+ "type": "string"
1325
+ }
1326
+ },
1327
+ {
1328
+ "name": "dry-run",
1329
+ "schema": {
1330
+ "type": "boolean",
1331
+ "default": false
1332
+ }
1333
+ },
1334
+ {
1335
+ "name": "show-prompt",
1336
+ "schema": {
1337
+ "type": "boolean",
1338
+ "default": false
1339
+ }
1340
+ },
1341
+ {
1342
+ "name": "fail-on",
1343
+ "schema": {
1344
+ "type": "string",
1345
+ "enum": [
1346
+ "warning",
1347
+ "error",
1348
+ "critical"
1349
+ ],
1350
+ "default": "error"
1351
+ }
1352
+ },
1353
+ {
1354
+ "name": "output",
1355
+ "schema": {
1356
+ "type": "string"
1357
+ },
1358
+ "file": {
1359
+ "mode": "write",
1360
+ "encoding": "utf-8"
1361
+ }
1362
+ },
1363
+ {
1364
+ "name": "report-format",
1365
+ "schema": {
1366
+ "type": "string",
1367
+ "enum": [
1368
+ "json",
1369
+ "text",
1370
+ "yaml"
1371
+ ],
1372
+ "default": "json"
1373
+ }
1374
+ }
1375
+ ],
1376
+ "env": {
1377
+ "CURSOR_API_KEY": {
1378
+ "sensitive": true
1379
+ },
1380
+ "GEMINI_API_KEY": {
1381
+ "sensitive": true
1382
+ },
1383
+ "OPENAI_API_KEY": {
1384
+ "sensitive": true
1385
+ },
1386
+ "ANTHROPIC_API_KEY": {
1387
+ "sensitive": true
1388
+ }
1389
+ }
1390
+ },
1391
+ "propose-acceptance-criteria": {
1392
+ "effects": {
1393
+ "network": {
1394
+ "description": "LLM API calls to configured provider",
1395
+ "idempotent": true
1396
+ }
1397
+ },
1398
+ "options": [
1399
+ {
1400
+ "name": "config",
1401
+ "schema": {
1402
+ "type": "string"
1403
+ },
1404
+ "file": {
1405
+ "mode": "read",
1406
+ "exists": true,
1407
+ "encoding": "utf-8"
1408
+ }
1409
+ },
1410
+ {
1411
+ "name": "adapter",
1412
+ "schema": {
1413
+ "type": "string",
1414
+ "enum": [
1415
+ "cursor",
1416
+ "claude",
1417
+ "openai",
1418
+ "gemini",
1419
+ "mock"
1420
+ ]
1421
+ }
1422
+ },
1423
+ {
1424
+ "name": "model",
1425
+ "schema": {
1426
+ "type": "string"
1427
+ }
1428
+ },
1429
+ {
1430
+ "name": "dry-run",
1431
+ "schema": {
1432
+ "type": "boolean",
1433
+ "default": false
1434
+ }
1435
+ },
1436
+ {
1437
+ "name": "show-prompt",
1438
+ "schema": {
1439
+ "type": "boolean",
1440
+ "default": false
1441
+ }
1442
+ },
1443
+ {
1444
+ "name": "fail-on",
1445
+ "schema": {
1446
+ "type": "string",
1447
+ "enum": [
1448
+ "warning",
1449
+ "error",
1450
+ "critical"
1451
+ ],
1452
+ "default": "error"
1453
+ }
1454
+ },
1455
+ {
1456
+ "name": "output",
1457
+ "schema": {
1458
+ "type": "string"
1459
+ },
1460
+ "file": {
1461
+ "mode": "write",
1462
+ "encoding": "utf-8"
1463
+ }
1464
+ },
1465
+ {
1466
+ "name": "report-format",
1467
+ "schema": {
1468
+ "type": "string",
1469
+ "enum": [
1470
+ "json",
1471
+ "text",
1472
+ "yaml"
1473
+ ],
1474
+ "default": "json"
1475
+ }
1476
+ }
1477
+ ],
1478
+ "env": {
1479
+ "CURSOR_API_KEY": {
1480
+ "sensitive": true
1481
+ },
1482
+ "GEMINI_API_KEY": {
1483
+ "sensitive": true
1484
+ },
1485
+ "OPENAI_API_KEY": {
1486
+ "sensitive": true
1487
+ },
1488
+ "ANTHROPIC_API_KEY": {
1489
+ "sensitive": true
1490
+ }
1491
+ }
1492
+ }
1493
+ };
1494
+ function deriveCommandPolicy(commandId, optionValues) {
1495
+ const def = commandDefinitions[commandId];
1496
+ if (!def) throw new Error(`Unknown command: ${commandId}`);
1497
+ const cmdDef = def;
1498
+ const options = {};
1499
+ const activeOptions = [];
1500
+ for (const optDef of cmdDef.options ?? []) {
1501
+ const value = optionValues[optDef.name];
1502
+ const specified = optDef.name in optionValues && value !== void 0;
1503
+ options[optDef.name] = { value, specified, definition: optDef };
1504
+ if (isOptionActive(optDef, value, specified)) {
1505
+ activeOptions.push(optDef.name);
1506
+ }
1507
+ }
1508
+ const policy = derivePolicy({
1509
+ commandId,
1510
+ commandEffects: cmdDef.effects,
1511
+ options,
1512
+ env: cmdDef.env
1513
+ });
1514
+ return { command: commandId, activeOptions, policy };
1515
+ }
1516
+
1517
+ // src/generated/program.ts
1518
+ function createProgram(handlers2, version) {
1519
+ const program = new Command();
1520
+ program.name("speckeeper").version(version, "-V, --version").description("Requirements and design management framework with TypeScript DSL.");
1521
+ program.option("--introspect", "Output derived policy as JSON without executing the command");
1522
+ 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) => {
1523
+ const globalOpts = cmd.optsWithGlobals();
1524
+ if (globalOpts.introspect) {
1525
+ const policy = deriveCommandPolicy("init", opts);
1526
+ console.log(JSON.stringify(policy, null, 2));
1527
+ return;
1528
+ }
1529
+ await handlers2.init(opts, globalOpts);
1530
+ });
1531
+ 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) => {
1532
+ const globalOpts = cmd.optsWithGlobals();
1533
+ if (globalOpts.introspect) {
1534
+ const policy = deriveCommandPolicy("build", opts);
1535
+ console.log(JSON.stringify(policy, null, 2));
1536
+ return;
1537
+ }
1538
+ await handlers2.build(opts, globalOpts);
1539
+ });
1540
+ 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) => {
1541
+ const globalOpts = cmd.optsWithGlobals();
1542
+ if (globalOpts.introspect) {
1543
+ const policy = deriveCommandPolicy("lint", opts);
1544
+ console.log(JSON.stringify(policy, null, 2));
1545
+ return;
1546
+ }
1547
+ await handlers2.lint(opts, globalOpts);
1548
+ });
1549
+ 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) => {
1550
+ const globalOpts = cmd.optsWithGlobals();
1551
+ if (globalOpts.introspect) {
1552
+ const policy = deriveCommandPolicy("drift", opts);
1553
+ console.log(JSON.stringify(policy, null, 2));
1554
+ return;
1555
+ }
1556
+ await handlers2.drift(opts, globalOpts);
1557
+ });
1558
+ 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) => {
1559
+ const globalOpts = cmd.optsWithGlobals();
1560
+ if (globalOpts.introspect) {
1561
+ const policy = deriveCommandPolicy("check", opts);
1562
+ console.log(JSON.stringify(policy, null, 2));
1563
+ return;
1564
+ }
1565
+ await handlers2.check(type, opts, globalOpts);
1566
+ });
1567
+ 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) => {
1568
+ const globalOpts = cmd.optsWithGlobals();
1569
+ if (globalOpts.introspect) {
1570
+ const policy = deriveCommandPolicy("new", opts);
1571
+ console.log(JSON.stringify(policy, null, 2));
1572
+ return;
1573
+ }
1574
+ await handlers2.new(type, opts, globalOpts);
1575
+ });
1576
+ 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) => {
1577
+ const globalOpts = cmd.optsWithGlobals();
1578
+ if (globalOpts.introspect) {
1579
+ const policy = deriveCommandPolicy("impact", opts);
1580
+ console.log(JSON.stringify(policy, null, 2));
1581
+ return;
1582
+ }
1583
+ await handlers2.impact(id, opts, globalOpts);
1584
+ });
1585
+ 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) => {
1586
+ const globalOpts = cmd.optsWithGlobals();
1587
+ if (globalOpts.introspect) {
1588
+ const policy = deriveCommandPolicy("scaffold", opts);
1589
+ console.log(JSON.stringify(policy, null, 2));
1590
+ return;
1591
+ }
1592
+ await handlers2.scaffold(opts, globalOpts);
1593
+ });
1594
+ 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) => {
1595
+ const globalOpts = cmd.optsWithGlobals();
1596
+ if (globalOpts.introspect) {
1597
+ const policy = deriveCommandPolicy("convert", opts);
1598
+ console.log(JSON.stringify(policy, null, 2));
1599
+ return;
1600
+ }
1601
+ await handlers2.convert(file, opts, globalOpts);
1602
+ });
1603
+ 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) => {
1604
+ const globalOpts = cmd.optsWithGlobals();
1605
+ if (globalOpts.introspect) {
1606
+ const policy = deriveCommandPolicy("audit-requirements", opts);
1607
+ console.log(JSON.stringify(policy, null, 2));
1608
+ return;
1609
+ }
1610
+ await handlers2.auditRequirements(opts, globalOpts);
1611
+ });
1612
+ 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) => {
1613
+ const globalOpts = cmd.optsWithGlobals();
1614
+ if (globalOpts.introspect) {
1615
+ const policy = deriveCommandPolicy("propose-trace-links", opts);
1616
+ console.log(JSON.stringify(policy, null, 2));
1617
+ return;
1618
+ }
1619
+ await handlers2.proposeTraceLinks(opts, globalOpts);
1620
+ });
1621
+ 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) => {
1622
+ const globalOpts = cmd.optsWithGlobals();
1623
+ if (globalOpts.introspect) {
1624
+ const policy = deriveCommandPolicy("explain-impact", opts);
1625
+ console.log(JSON.stringify(policy, null, 2));
1626
+ return;
1627
+ }
1628
+ await handlers2.explainImpact(opts, globalOpts);
1629
+ });
1630
+ 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) => {
1631
+ const globalOpts = cmd.optsWithGlobals();
1632
+ if (globalOpts.introspect) {
1633
+ const policy = deriveCommandPolicy("propose-acceptance-criteria", opts);
1634
+ console.log(JSON.stringify(policy, null, 2));
1635
+ return;
1636
+ }
1637
+ await handlers2.proposeAcceptanceCriteria(specIds, opts, globalOpts);
1638
+ });
1639
+ return program;
1640
+ }
538
1641
  var defaultConfig = {
539
1642
  srcDir: "src",
540
1643
  designDir: "design",
@@ -1961,6 +3064,8 @@ async function runInit(options = {}) {
1961
3064
  console.log(chalk4.gray(" Please ensure the package is properly installed."));
1962
3065
  return;
1963
3066
  }
3067
+ const isYaml = options.format === "yaml";
3068
+ const skipForYaml = /* @__PURE__ */ new Set(["design/requirements.ts"]);
1964
3069
  let packageJsonCreated = false;
1965
3070
  copyTemplateDir(templatesDir, cwd, projectName, options.force || false, (relativePath, created) => {
1966
3071
  if (created) {
@@ -1971,25 +3076,29 @@ async function runInit(options = {}) {
1971
3076
  } else {
1972
3077
  console.log(chalk4.yellow(` Skipped: ${relativePath} (already exists)`));
1973
3078
  }
1974
- });
3079
+ }, "", isYaml ? skipForYaml : void 0);
3080
+ if (isYaml) {
3081
+ writeYamlInitFiles(cwd, options.force || false);
3082
+ }
1975
3083
  console.log("");
1976
3084
  console.log(chalk4.cyan(" Project initialized successfully!"));
1977
3085
  console.log("");
3086
+ const dataFormat = isYaml ? "design/*.yaml" : "design/*.ts using defineSpecs()";
1978
3087
  console.log(" Next steps:");
1979
3088
  if (packageJsonCreated) {
1980
3089
  console.log(chalk4.gray(" 1. Run `npm install` to install dependencies"));
1981
- console.log(chalk4.gray(" 2. Add spec data in design/*.ts using defineSpecs()"));
3090
+ console.log(chalk4.gray(` 2. Add spec data in ${dataFormat}`));
1982
3091
  console.log(chalk4.gray(" 3. Import new spec files in design/index.ts"));
1983
3092
  console.log(chalk4.gray(" 4. Run `npx speckeeper lint` to validate"));
1984
3093
  } else {
1985
3094
  console.log(chalk4.gray(" 1. Add speckeeper and zod to your package.json dependencies"));
1986
3095
  console.log(chalk4.gray(' 2. Ensure "type": "module" is set in package.json'));
1987
- console.log(chalk4.gray(" 3. Add spec data in design/*.ts using defineSpecs()"));
3096
+ console.log(chalk4.gray(` 3. Add spec data in ${dataFormat}`));
1988
3097
  console.log(chalk4.gray(" 4. Import new spec files in design/index.ts"));
1989
3098
  console.log(chalk4.gray(" 5. Run `npx speckeeper lint` to validate"));
1990
3099
  }
1991
3100
  }
1992
- function copyTemplateDir(srcDir, destDir, projectName, force, onFile, relativePath = "") {
3101
+ function copyTemplateDir(srcDir, destDir, projectName, force, onFile, relativePath = "", skipRelPaths) {
1993
3102
  const entries = readdirSync(srcDir);
1994
3103
  for (const entry of entries) {
1995
3104
  const srcPath = join(srcDir, entry);
@@ -2002,8 +3111,9 @@ function copyTemplateDir(srcDir, destDir, projectName, force, onFile, relativePa
2002
3111
  mkdirSync(destPath, { recursive: true });
2003
3112
  onFile(relPath + "/", true);
2004
3113
  }
2005
- copyTemplateDir(srcPath, destPath, projectName, force, onFile, relPath);
3114
+ copyTemplateDir(srcPath, destPath, projectName, force, onFile, relPath, skipRelPaths);
2006
3115
  } else {
3116
+ if (skipRelPaths?.has(relPath)) continue;
2007
3117
  if (!force && existsSync(destPath)) {
2008
3118
  onFile(relPath, false);
2009
3119
  continue;
@@ -2019,6 +3129,91 @@ function copyTemplateDir(srcDir, destDir, projectName, force, onFile, relativePa
2019
3129
  }
2020
3130
  }
2021
3131
  }
3132
+ function writeYamlInitFiles(cwd, force) {
3133
+ const designDir = join(cwd, "design");
3134
+ if (!existsSync(designDir)) {
3135
+ mkdirSync(designDir, { recursive: true });
3136
+ }
3137
+ const reqYaml = join(designDir, "requirements.yaml");
3138
+ if (force || !existsSync(reqYaml)) {
3139
+ writeFileSync(reqYaml, `# Requirements
3140
+ model: requirement
3141
+ specs:
3142
+ - id: REQ-001
3143
+ name: User Authentication
3144
+ type: functional
3145
+ priority: must
3146
+ description: Users can authenticate using email and password
3147
+ acceptanceCriteria:
3148
+ - id: REQ-001-01
3149
+ description: Valid credentials grant access
3150
+ verificationMethod: test
3151
+ - id: REQ-001-02
3152
+ description: Invalid credentials show error message
3153
+ verificationMethod: test
3154
+ `);
3155
+ console.log(chalk4.green(" Created: design/requirements.yaml"));
3156
+ }
3157
+ const indexTs = join(designDir, "index.ts");
3158
+ if (force || !existsSync(indexTs)) {
3159
+ writeFileSync(indexTs, `/**
3160
+ * Design entry point
3161
+ */
3162
+ import { mergeSpecs, loadYamlDir } from 'speckeeper';
3163
+ import { allModels } from './_models/index.ts';
3164
+
3165
+ const yamlSpecs = loadYamlDir(import.meta.dirname, allModels);
3166
+
3167
+ export default mergeSpecs(...yamlSpecs);
3168
+ `);
3169
+ console.log(chalk4.green(" Created: design/index.ts (yaml mode)"));
3170
+ }
3171
+ }
3172
+ async function runConvert(file, options = {}) {
3173
+ const filePath = resolve(file);
3174
+ if (!existsSync(filePath)) {
3175
+ console.error(chalk4.red(` Error: File not found: ${filePath}`));
3176
+ process.exit(1);
3177
+ }
3178
+ if (!filePath.endsWith(".ts") && !filePath.endsWith(".js") && !filePath.endsWith(".mjs")) {
3179
+ console.error(chalk4.red(" Error: Source file must be a .ts, .js, or .mjs file"));
3180
+ process.exit(1);
3181
+ }
3182
+ console.log(chalk4.cyan("speckeeper convert"));
3183
+ console.log(chalk4.gray(` Source: ${filePath}`));
3184
+ console.log("");
3185
+ let specModule;
3186
+ try {
3187
+ const imported = await import(filePath);
3188
+ specModule = imported.default ?? imported;
3189
+ } catch (err) {
3190
+ console.error(chalk4.red(` Error: Failed to import ${filePath}`));
3191
+ console.error(chalk4.gray(` ${err instanceof Error ? err.message : String(err)}`));
3192
+ process.exit(1);
3193
+ }
3194
+ if (!specModule?.entries || !Array.isArray(specModule.entries)) {
3195
+ console.error(chalk4.red(" Error: File does not export a valid SpecModule (missing entries array)"));
3196
+ console.error(chalk4.gray(" The file must export a SpecModule via defineSpecs()"));
3197
+ process.exit(1);
3198
+ }
3199
+ 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 })) };
3200
+ const yamlString = stringify(yamlData, {
3201
+ lineWidth: 120,
3202
+ defaultStringType: "PLAIN",
3203
+ defaultKeyType: "PLAIN"
3204
+ });
3205
+ if (options.dryRun) {
3206
+ console.log(chalk4.yellow(" Dry run \u2014 showing conversion result:"));
3207
+ console.log("");
3208
+ console.log(yamlString);
3209
+ return;
3210
+ }
3211
+ const outputPath = options.output ? resolve(options.output) : join(dirname(filePath), basename(filePath).replace(/\.(ts|js|mjs)$/, ".yaml"));
3212
+ writeFileSync(outputPath, yamlString);
3213
+ console.log(chalk4.green(` Created: ${outputPath}`));
3214
+ console.log("");
3215
+ console.log(chalk4.gray(" Remember to update design/index.ts to use loadYamlDir() for YAML files."));
3216
+ }
2022
3217
 
2023
3218
  // src/scaffold/mermaid-parser.ts
2024
3219
  function extractMermaidBlocks(markdown) {
@@ -2549,12 +3744,27 @@ function generateModelFile(node, _incomingEdges, _outgoingEdges, _allNodes) {
2549
3744
  content
2550
3745
  };
2551
3746
  }
2552
- function generateSpecDataFile(node) {
3747
+ function generateSpecDataFile(node, format = "ts") {
2553
3748
  const templateInfo = resolveModelTemplate(node.id, node.classes, node.subgraph);
2554
3749
  const className = `${templateInfo.modelName}Model`;
2555
3750
  const typeName = templateInfo.modelName;
2556
3751
  const varName = toCamelCase(templateInfo.modelName) + "s";
2557
3752
  const fileName = templateInfo.fileName;
3753
+ if (format === "yaml") {
3754
+ const content2 = `# ${templateInfo.modelName} Specifications
3755
+ #
3756
+ # Generated by speckeeper scaffold \u2014 add your specs below.
3757
+ model: ${templateInfo.fileName}
3758
+ specs:
3759
+ # - id: ${templateInfo.defaultIdPrefix}-001
3760
+ # name: "..."
3761
+ # description: "..."
3762
+ `;
3763
+ return {
3764
+ relativePath: `${fileName}.yaml`,
3765
+ content: content2
3766
+ };
3767
+ }
2558
3768
  const content = `/**
2559
3769
  * ${templateInfo.modelName} Specifications
2560
3770
  *
@@ -2580,7 +3790,7 @@ export default defineSpecs(
2580
3790
  function toCamelCase(pascalCase) {
2581
3791
  return pascalCase.charAt(0).toLowerCase() + pascalCase.slice(1);
2582
3792
  }
2583
- function generateDesignIndex(speckeeperNodes) {
3793
+ function generateDesignIndex(speckeeperNodes, format = "ts") {
2584
3794
  const generated = /* @__PURE__ */ new Set();
2585
3795
  const specFiles = [];
2586
3796
  for (const node of speckeeperNodes) {
@@ -2594,6 +3804,21 @@ function generateDesignIndex(speckeeperNodes) {
2594
3804
  fileName: templateInfo.fileName
2595
3805
  });
2596
3806
  }
3807
+ if (format === "yaml") {
3808
+ const content2 = `/**
3809
+ * Design entry point \u2014 generated by speckeeper scaffold
3810
+ *
3811
+ * YAML spec files in this directory are auto-discovered by loadYamlDir().
3812
+ */
3813
+ import { mergeSpecs, loadYamlDir } from 'speckeeper';
3814
+ import { allModels } from './_models';
3815
+
3816
+ const yamlSpecs = loadYamlDir(import.meta.dirname, allModels);
3817
+
3818
+ export default mergeSpecs(...yamlSpecs);
3819
+ `;
3820
+ return { relativePath: "index.ts", content: content2 };
3821
+ }
2597
3822
  const imports = specFiles.map((f) => `import ${f.varName} from './${f.fileName}';`).join("\n");
2598
3823
  const args = specFiles.map((f) => f.varName).join(", ");
2599
3824
  const content = `/**
@@ -2609,7 +3834,7 @@ export default mergeSpecs(${args});
2609
3834
  content
2610
3835
  };
2611
3836
  }
2612
- function generateAllModelFiles(speckeeperNodes, resolvedEdges, allNodes) {
3837
+ function generateAllModelFiles(speckeeperNodes, resolvedEdges, allNodes, format = "ts") {
2613
3838
  const files = [];
2614
3839
  const generated = /* @__PURE__ */ new Set();
2615
3840
  const templateNodeGroups = /* @__PURE__ */ new Map();
@@ -2632,9 +3857,9 @@ function generateAllModelFiles(speckeeperNodes, resolvedEdges, allNodes) {
2632
3857
  resolvedEdges.filter((e) => groupNodeIds.has(e.targetId));
2633
3858
  resolvedEdges.filter((e) => groupNodeIds.has(e.sourceId));
2634
3859
  files.push(generateModelFile(node));
2635
- files.push(generateSpecDataFile(node));
3860
+ files.push(generateSpecDataFile(node, format));
2636
3861
  }
2637
- files.push(generateDesignIndex(speckeeperNodes));
3862
+ files.push(generateDesignIndex(speckeeperNodes, format));
2638
3863
  return files;
2639
3864
  }
2640
3865
 
@@ -2727,7 +3952,8 @@ async function scaffoldCommand(options) {
2727
3952
  );
2728
3953
  printDiagnostics(diagnostics);
2729
3954
  const outputDir = options.output ? resolve(options.output) : join(process.cwd(), "design");
2730
- const modelFiles = generateAllModelFiles(speckeeperNodes, resolved, flowchart.nodes);
3955
+ const specFormat = options.format ?? "ts";
3956
+ const modelFiles = generateAllModelFiles(speckeeperNodes, resolved, flowchart.nodes, specFormat);
2731
3957
  const indexFile = generateModelsIndex(modelFiles);
2732
3958
  const allFiles = [...modelFiles, indexFile];
2733
3959
  console.log("");
@@ -3330,13 +4556,13 @@ async function commandExplainImpact(opts) {
3330
4556
  }
3331
4557
  }
3332
4558
  function readStdin() {
3333
- return new Promise((resolve3, reject) => {
4559
+ return new Promise((resolve4, reject) => {
3334
4560
  const chunks = [];
3335
4561
  process.stdin.on("data", (chunk) => chunks.push(chunk));
3336
- process.stdin.on("end", () => resolve3(Buffer.concat(chunks).toString("utf-8")));
4562
+ process.stdin.on("end", () => resolve4(Buffer.concat(chunks).toString("utf-8")));
3337
4563
  process.stdin.on("error", reject);
3338
4564
  if (process.stdin.isTTY) {
3339
- resolve3("");
4565
+ resolve4("");
3340
4566
  }
3341
4567
  });
3342
4568
  }
@@ -3386,68 +4612,78 @@ function getVersion() {
3386
4612
  return "0.0.0";
3387
4613
  }
3388
4614
  }
3389
- var program = new Command();
3390
- program.name("speckeeper").description("Requirements and design management framework with TypeScript DSL").version(getVersion());
3391
- 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").option("-v, --verbose", "Show detailed output").action(buildCommand);
3392
- 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").option("--fix", "Attempt to fix auto-fixable issues").option("-f, --format <format>", "Output format: text, json, github", "text").action(lintCommand);
3393
- 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").option("-f, --format <format>", "Output format: text, json, diff", "text").option("--fail-on-drift", "Exit with code 1 if drift is detected (for CI)").action(driftCommand);
3394
- program.command("check").description("Check external SSOT conformance (including custom models)").argument("[type]", "Type of check: external-ssot, openapi, ddl, iac, custom, all, test").option("-c, --config <path>", "Path to config file").option("--strict", "Treat warnings as errors").option("-v, --verbose", "Show detailed output").option("--coverage", "Check if all testable acceptance criteria are covered by TestRefs").action(checkCommand);
3395
- program.command("new").description("Create a new element with auto-generated ID").argument("<type>", "Type: requirement, usecase, entity, component, screen, flow, error-case, term").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").action(newCommand);
3396
- program.command("impact").description("Analyze impact of changes to an ID").argument("<id>", "ID to analyze (e.g., REQ-001, ENT-ORDER)").option("-c, --config <path>", "Path to config file").option("-d, --depth <depth>", "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(impactCommand);
3397
- program.command("init").description("Initialize a new speckeeper project with starter templates").option("-f, --force", "Overwrite existing files").action(runInit);
3398
- program.command("scaffold").description("Generate _models/ from a mermaid flowchart definition").requiredOption("-s, --source <path>", "Path to Markdown file containing mermaid flowchart").option("-o, --output <path>", "Output directory (default: design/)").option("-f, --force", "Overwrite existing files").option("--dry-run", "Preview generated files without writing").action(scaffoldCommand);
3399
- var llmOptions = (cmd) => cmd.option("-a, --adapter <name>", "SDK adapter (cursor, claude, openai, gemini, mock)").option("--model <name>", "LLM model override").option("-n, --dry-run", "Output prompt without calling LLM").option("--fail-on <level>", "Minimum severity for non-zero exit (warning, error, critical)", "error").option("-o, --output <file>", "Write result to a file instead of stdout").option("--report-format <fmt>", "Output format (json, text, yaml)", "text");
3400
- llmOptions(
3401
- program.command("audit-requirements").description("LLM-based requirement quality audit").option("-c, --config <path>", "Path to config file")
3402
- ).action((opts) => {
3403
- commandAuditRequirements({
3404
- config: opts.config,
3405
- adapter: opts.adapter,
3406
- model: opts.model,
3407
- dryRun: opts.dryRun,
3408
- failOn: opts.failOn,
3409
- output: opts.output,
3410
- reportFormat: opts.reportFormat
3411
- });
3412
- });
3413
- llmOptions(
3414
- program.command("propose-trace-links").description("LLM-based traceability link proposal").option("-c, --config <path>", "Path to config file")
3415
- ).action((opts) => {
3416
- commandProposeTraceLinks({
3417
- config: opts.config,
3418
- adapter: opts.adapter,
3419
- model: opts.model,
3420
- dryRun: opts.dryRun,
3421
- failOn: opts.failOn,
3422
- output: opts.output,
3423
- reportFormat: opts.reportFormat
3424
- });
3425
- });
3426
- llmOptions(
3427
- program.command("explain-impact").description("LLM-based explanation of impact analysis output")
3428
- ).action((opts) => {
3429
- commandExplainImpact({
3430
- adapter: opts.adapter,
3431
- model: opts.model,
3432
- dryRun: opts.dryRun,
3433
- failOn: opts.failOn,
3434
- output: opts.output,
3435
- reportFormat: opts.reportFormat
3436
- });
3437
- });
3438
- llmOptions(
3439
- program.command("propose-acceptance-criteria [specIds...]").description("LLM-based acceptance criteria proposal").option("-c, --config <path>", "Path to config file")
3440
- ).action((specIds, opts) => {
3441
- commandProposeAcceptanceCriteria(specIds, {
3442
- config: opts.config,
3443
- adapter: opts.adapter,
3444
- model: opts.model,
3445
- dryRun: opts.dryRun,
3446
- failOn: opts.failOn,
3447
- output: opts.output,
3448
- reportFormat: opts.reportFormat
3449
- });
3450
- });
3451
- program.parse();
4615
+ var handlers = {
4616
+ init: async (opts) => {
4617
+ await runInit(opts);
4618
+ },
4619
+ build: async (opts) => {
4620
+ await buildCommand(opts);
4621
+ },
4622
+ lint: async (opts) => {
4623
+ await lintCommand(opts);
4624
+ },
4625
+ drift: async (opts) => {
4626
+ await driftCommand(opts);
4627
+ },
4628
+ check: async (type, opts) => {
4629
+ await checkCommand(type, opts);
4630
+ },
4631
+ new: async (type, opts) => {
4632
+ await newCommand({ type, output: opts.output, dryRun: opts.dryRun });
4633
+ },
4634
+ impact: async (id, opts) => {
4635
+ await impactCommand(id, opts);
4636
+ },
4637
+ scaffold: async (opts) => {
4638
+ await scaffoldCommand(opts);
4639
+ },
4640
+ convert: async (file, opts) => {
4641
+ await runConvert(file, opts);
4642
+ },
4643
+ auditRequirements: async (opts) => {
4644
+ await commandAuditRequirements({
4645
+ config: opts.config,
4646
+ adapter: opts.adapter,
4647
+ model: opts.model,
4648
+ dryRun: opts.dryRun,
4649
+ failOn: opts.failOn,
4650
+ output: opts.output,
4651
+ reportFormat: opts.reportFormat
4652
+ });
4653
+ },
4654
+ proposeTraceLinks: async (opts) => {
4655
+ await commandProposeTraceLinks({
4656
+ config: opts.config,
4657
+ adapter: opts.adapter,
4658
+ model: opts.model,
4659
+ dryRun: opts.dryRun,
4660
+ failOn: opts.failOn,
4661
+ output: opts.output,
4662
+ reportFormat: opts.reportFormat
4663
+ });
4664
+ },
4665
+ explainImpact: async (opts) => {
4666
+ await commandExplainImpact({
4667
+ adapter: opts.adapter,
4668
+ model: opts.model,
4669
+ dryRun: opts.dryRun,
4670
+ failOn: opts.failOn,
4671
+ output: opts.output,
4672
+ reportFormat: opts.reportFormat
4673
+ });
4674
+ },
4675
+ proposeAcceptanceCriteria: async (specIds, opts) => {
4676
+ await commandProposeAcceptanceCriteria(specIds, {
4677
+ config: opts.config,
4678
+ adapter: opts.adapter,
4679
+ model: opts.model,
4680
+ dryRun: opts.dryRun,
4681
+ failOn: opts.failOn,
4682
+ output: opts.output,
4683
+ reportFormat: opts.reportFormat
4684
+ });
4685
+ }
4686
+ };
4687
+ createProgram(handlers, getVersion()).parse();
3452
4688
  //# sourceMappingURL=cli.js.map
3453
4689
  //# sourceMappingURL=cli.js.map