@fairmint/captable-ai 0.1.22 → 0.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +1106 -1049
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -448,866 +448,6 @@ async function runAuthStatus(args) {
448
448
  ]);
449
449
  }
450
450
 
451
- // src/commands/commands.ts
452
- var COMMAND_REGISTRY = [
453
- {
454
- name: "login",
455
- group: "auth",
456
- description: "Authenticate via browser-based login.",
457
- usage: "captable-ai login",
458
- requiresAuth: false,
459
- requiresPortal: false
460
- },
461
- {
462
- name: "logout",
463
- group: "auth",
464
- description: "Revoke tokens and clear local credentials.",
465
- usage: "captable-ai logout",
466
- requiresAuth: false,
467
- requiresPortal: false
468
- },
469
- {
470
- name: "auth status",
471
- group: "auth",
472
- description: "Show authentication status, token expiry, and active company.",
473
- usage: "captable-ai auth status",
474
- requiresAuth: false,
475
- requiresPortal: false
476
- },
477
- {
478
- name: "company list",
479
- group: "company",
480
- description: "List available companies.",
481
- usage: "captable-ai company list",
482
- requiresAuth: true,
483
- requiresPortal: false
484
- },
485
- {
486
- name: "company use",
487
- group: "company",
488
- description: "Set the active company by ID or name.",
489
- usage: "captable-ai company use <id-or-name>",
490
- requiresAuth: true,
491
- requiresPortal: false
492
- },
493
- {
494
- name: "company current",
495
- group: "company",
496
- description: "Show the active company.",
497
- usage: "captable-ai company current",
498
- requiresAuth: true,
499
- requiresPortal: false
500
- },
501
- {
502
- name: "company create",
503
- group: "company",
504
- description: "Create a new test portal with ISSUER OCF object. Requires Fairmint super admin.",
505
- usage: "captable-ai company create --name <company-name> [--legal-name <name>] [--domain <domain>] [--country <code>] [--formation-date <YYYY-MM-DD>] [--currency <code>] [--json]",
506
- requiresAuth: true,
507
- requiresPortal: false,
508
- flags: [
509
- { name: "name", description: "Company display name (required).", type: "string" },
510
- {
511
- name: "legal-name",
512
- description: "Legal entity name (defaults to --name).",
513
- type: "string"
514
- },
515
- { name: "domain", description: "Portal domain.", type: "string" },
516
- { name: "country", description: "ISO 3166-1 alpha-2 country code.", type: "string" },
517
- { name: "formation-date", description: "Incorporation date (YYYY-MM-DD).", type: "string" },
518
- { name: "currency", description: "Currency ISO 4217 (default: USD).", type: "string" }
519
- ]
520
- },
521
- {
522
- name: "company delete",
523
- group: "company",
524
- description: "Delete a test portal and all child data. Dev-only. Requires Fairmint super admin.",
525
- usage: "captable-ai company delete <company-id> [--yes] [--json]",
526
- requiresAuth: true,
527
- requiresPortal: false,
528
- flags: [{ name: "yes", description: "Skip the confirmation prompt.", type: "boolean" }]
529
- },
530
- {
531
- name: "onboarding status",
532
- group: "onboarding",
533
- description: "Show the next first-workspace or import action. Works for authenticated users with zero companies.",
534
- usage: "captable-ai onboarding status [--session <import-session-id>] [--json]",
535
- requiresAuth: true,
536
- requiresPortal: false,
537
- flags: [
538
- {
539
- name: "session",
540
- description: "Inspect this import session instead of local workspace state.",
541
- type: "string"
542
- }
543
- ]
544
- },
545
- {
546
- name: "onboarding setup",
547
- group: "onboarding",
548
- description: "Idempotently create the authenticated user's first production workspace. Only --accept-terms is required; the company profile is read from uploaded documents.",
549
- usage: "captable-ai onboarding setup --accept-terms [--legal-name <name>] [--company-type <type>] [--country <code>] [--role <role>] [--other-role <role>] [--cap-table-source <source>] [--other-cap-table-source <source>] [--stakeholder-count <bucket>] [--json]",
550
- requiresAuth: true,
551
- requiresPortal: false,
552
- flags: [
553
- {
554
- name: "accept-terms",
555
- description: "Confirm acceptance of Fairmint's Terms of Service (required).",
556
- type: "boolean"
557
- },
558
- {
559
- name: "legal-name",
560
- description: "Company name. Left unset until you or document extraction supplies one.",
561
- type: "string"
562
- },
563
- {
564
- name: "company-type",
565
- description: "Legal entity type. Left unrecorded when omitted.",
566
- type: "string",
567
- enum: ["us_c_corporation", "us_llc", "foreign_entity", "not_incorporated"]
568
- },
569
- {
570
- name: "country",
571
- description: "ISO 3166-1 alpha-2 code. Only with --company-type foreign_entity.",
572
- type: "string"
573
- },
574
- {
575
- name: "role",
576
- description: "Your role at the company.",
577
- type: "string",
578
- enum: [
579
- "CEO",
580
- "COO",
581
- "CMO",
582
- "CFO",
583
- "CTO",
584
- "CRO",
585
- "Director",
586
- "Founder",
587
- "co-founder",
588
- "co-CEO",
589
- "other"
590
- ]
591
- },
592
- {
593
- name: "other-role",
594
- description: "Free-text role. Required when --role other.",
595
- type: "string"
596
- },
597
- {
598
- name: "cap-table-source",
599
- description: "Where the cap table is maintained today.",
600
- type: "string",
601
- enum: ["none", "spreadsheet", "carta", "pulley", "angellist", "other"]
602
- },
603
- {
604
- name: "other-cap-table-source",
605
- description: "Free-text source. Required when --cap-table-source other.",
606
- type: "string"
607
- },
608
- {
609
- name: "stakeholder-count",
610
- description: "Approximate number of stakeholders on the cap table.",
611
- type: "string",
612
- enum: ["1_10", "11_25", "26_50", "50_100", "100_plus"]
613
- }
614
- ]
615
- },
616
- {
617
- name: "import start",
618
- group: "onboarding",
619
- description: "Start or reuse a secure import session for existing document upload APIs.",
620
- usage: "captable-ai import start [--json]",
621
- requiresAuth: true,
622
- requiresPortal: true
623
- },
624
- {
625
- name: "import status",
626
- group: "onboarding",
627
- description: "Show import processing progress and the next existing-pipeline action.",
628
- usage: "captable-ai import status <session-id> [--json]",
629
- requiresAuth: true,
630
- requiresPortal: false
631
- },
632
- {
633
- name: "summary",
634
- group: "captable",
635
- description: "Full cap table snapshot: capitalization, stakeholders, convertibles, metrics, and status.",
636
- usage: "captable-ai summary [--as-of YYYY-MM-DD] [--include-pending] [--skip-stakeholders] [--page overview] [--json]",
637
- requiresAuth: true,
638
- requiresPortal: true,
639
- flags: [
640
- {
641
- name: "as-of",
642
- description: "Historical snapshot date (YYYY-MM-DD).",
643
- type: "string"
644
- },
645
- {
646
- name: "include-pending",
647
- description: "Include draft objects in computation.",
648
- type: "boolean"
649
- },
650
- {
651
- name: "skip-stakeholders",
652
- description: "Omit stakeholderView section (faster).",
653
- type: "boolean"
654
- },
655
- {
656
- name: "page",
657
- description: "Use 'overview' for lightweight issuer/metrics/status.",
658
- type: "string",
659
- enum: ["overview"]
660
- }
661
- ]
662
- },
663
- {
664
- name: "objects list",
665
- group: "captable",
666
- description: "List OCF objects with filtering and pagination.",
667
- usage: "captable-ai objects list [--type TYPE] [--subtype SUBTYPE] [--status STATUS] [--limit N] [--cursor C] [--q QUERY] [--from YYYY-MM-DD] [--to YYYY-MM-DD] [--ids IDS] [--stakeholder ID] [--document ID] [--all] [--max-confidence N] [--json]",
668
- requiresAuth: true,
669
- requiresPortal: true,
670
- flags: [
671
- {
672
- name: "type",
673
- description: "Filter by top-level OCF type (comma-separated). Use `schemas list` for allowed values.",
674
- type: "string"
675
- },
676
- {
677
- name: "subtype",
678
- description: "Filter by TRANSACTION subtype (comma-separated). Use `schemas get TRANSACTION` for allowed values.",
679
- type: "string"
680
- },
681
- {
682
- name: "status",
683
- description: "Filter by status: draft or committed.",
684
- type: "string",
685
- enum: ["draft", "committed"]
686
- },
687
- { name: "limit", description: "Page size (1-250, default 100).", type: "number" },
688
- { name: "cursor", description: "Pagination cursor.", type: "string" },
689
- { name: "q", description: "Full-text search query.", type: "string" },
690
- {
691
- name: "from",
692
- description: "Filter objects with date >= (YYYY-MM-DD, inclusive).",
693
- type: "string"
694
- },
695
- {
696
- name: "to",
697
- description: "Filter objects with date <= (YYYY-MM-DD, inclusive).",
698
- type: "string"
699
- },
700
- { name: "ids", description: "Batch fetch by comma-separated IDs.", type: "string" },
701
- {
702
- name: "stakeholder",
703
- description: "Filter by OCF stakeholder id.",
704
- type: "string"
705
- },
706
- {
707
- name: "document",
708
- description: "Filter by source document s3 asset id.",
709
- type: "string"
710
- },
711
- {
712
- name: "all",
713
- description: "Follow pagination cursors until every matching object is returned.",
714
- type: "boolean"
715
- },
716
- {
717
- name: "max-confidence",
718
- description: "Keep objects with extraction confidence <= N. Requires --all.",
719
- type: "number"
720
- }
721
- ]
722
- },
723
- {
724
- name: "objects review-non-cash",
725
- group: "captable",
726
- description: "List unmarked convertible issuances whose stored evidence suggests possible non-cash consideration.",
727
- usage: "captable-ai objects review-non-cash [--status draft|committed] [--json]",
728
- requiresAuth: true,
729
- requiresPortal: true,
730
- flags: [
731
- {
732
- name: "status",
733
- description: "Review only latest draft or committed objects.",
734
- type: "string",
735
- enum: ["draft", "committed"]
736
- }
737
- ]
738
- },
739
- {
740
- name: "objects get",
741
- group: "captable",
742
- description: "Get a single OCF object with document, extraction details, and a vesting summary when present.",
743
- usage: "captable-ai objects get <object-id> [--json]",
744
- requiresAuth: true,
745
- requiresPortal: true
746
- },
747
- {
748
- name: "objects dump",
749
- group: "captable",
750
- description: "Write engine-shaped ocf.json from object ocf payloads.",
751
- usage: "captable-ai objects dump [--status committed|draft] [--output path]",
752
- requiresAuth: true,
753
- requiresPortal: true,
754
- flags: [
755
- {
756
- name: "status",
757
- description: "Filter by status: draft or committed. Default committed.",
758
- type: "string",
759
- enum: ["draft", "committed"]
760
- },
761
- {
762
- name: "output",
763
- description: "Write JSON to this file (global --output; implies --json).",
764
- type: "string"
765
- }
766
- ]
767
- },
768
- {
769
- name: "schemas list",
770
- group: "captable",
771
- description: "List available OCF object types.",
772
- usage: "captable-ai schemas list [--json]",
773
- requiresAuth: true,
774
- requiresPortal: false
775
- },
776
- {
777
- name: "schemas get",
778
- group: "captable",
779
- description: "Get the schema for an OCF object type.",
780
- usage: "captable-ai schemas get <object-type> [--json]",
781
- requiresAuth: true,
782
- requiresPortal: false
783
- },
784
- {
785
- name: "objects update",
786
- group: "captable",
787
- description: "Update an OCF object (committed or draft) by uploading a complete OCF payload (version-checked). Supply the payload via --stdin (piped JSON) or --file <path>. The --version is auto-fetched from the server if omitted.",
788
- usage: "captable-ai objects update <object-id> (--stdin | --file <path>) [--version N] [--json]",
789
- requiresAuth: true,
790
- requiresPortal: true,
791
- flags: [
792
- { name: "stdin", description: "Read complete OCF JSON payload from stdin.", type: "boolean" },
793
- {
794
- name: "file",
795
- description: "Path to a JSON file containing the complete OCF payload.",
796
- type: "string"
797
- },
798
- {
799
- name: "version",
800
- description: "Optimistic-concurrency version number. Auto-fetched from objects get if omitted.",
801
- type: "number"
802
- }
803
- ]
804
- },
805
- {
806
- name: "objects patch",
807
- group: "captable",
808
- description: "Patch an OCF object by uploading a partial OCF payload. The server shallow-merges the patch, validates the merged result, and writes a draft.",
809
- usage: "captable-ai objects patch <object-id> (--stdin | --file <path>) [--version N] [--json]",
810
- requiresAuth: true,
811
- requiresPortal: true,
812
- flags: [
813
- { name: "stdin", description: "Read partial OCF JSON payload from stdin.", type: "boolean" },
814
- {
815
- name: "file",
816
- description: "Path to a JSON file containing the partial OCF payload.",
817
- type: "string"
818
- },
819
- {
820
- name: "version",
821
- description: "Optional optimistic-concurrency version number.",
822
- type: "number"
823
- }
824
- ]
825
- },
826
- {
827
- name: "objects revert",
828
- group: "captable",
829
- description: "Preview or revert draft objects using backend dependency closure. Execution requires explicit final IDs (<object-id> or --objects) or --all.",
830
- usage: "captable-ai objects revert --dry-run [<object-id> | --objects id1,id2,... | --all] [--json]\ncaptable-ai objects revert (<object-id> | --objects id1,id2,... | --all) [--yes] [--json]",
831
- requiresAuth: true,
832
- requiresPortal: true,
833
- flags: [
834
- {
835
- name: "dry-run",
836
- description: "Preview selected/final IDs and dependency blockers without writing.",
837
- type: "boolean"
838
- },
839
- {
840
- name: "objects",
841
- description: "Comma-separated final object IDs to revert selectively.",
842
- type: "string"
843
- },
844
- {
845
- name: "all",
846
- description: "Revert all pending drafts for the active company.",
847
- type: "boolean"
848
- },
849
- {
850
- name: "yes",
851
- description: "Skip the confirmation prompt when using --all.",
852
- type: "boolean"
853
- }
854
- ]
855
- },
856
- {
857
- name: "objects delete",
858
- group: "captable",
859
- description: "Permanently delete an OCF object. By default deletes only the latest version; use --delete-all to remove all versions. Supports --expected-version for concurrency.",
860
- usage: "captable-ai objects delete <objectId> [--delete-all] [--expected-version N] [--yes] [--json]",
861
- requiresAuth: true,
862
- requiresPortal: true,
863
- flags: [
864
- {
865
- name: "delete-all",
866
- description: "Delete all versions, not just the latest.",
867
- type: "boolean"
868
- },
869
- {
870
- name: "expected-version",
871
- description: "Expected version for optimistic concurrency check.",
872
- type: "number"
873
- },
874
- {
875
- name: "yes",
876
- description: "Skip the confirmation prompt.",
877
- type: "boolean"
878
- }
879
- ]
880
- },
881
- {
882
- name: "objects versions",
883
- group: "captable",
884
- description: "List versions of an OCF object (draft vs committed).",
885
- usage: "captable-ai objects versions <object-id> [--json]",
886
- requiresAuth: true,
887
- requiresPortal: true
888
- },
889
- {
890
- name: "export",
891
- group: "captable",
892
- description: "Export the cap table as an Excel workbook. Returns a presigned download URL valid for 1 hour.",
893
- usage: "captable-ai export [--as-of YYYY-MM-DD] [--show-empty-fields] [--json]",
894
- requiresAuth: true,
895
- requiresPortal: true,
896
- flags: [
897
- {
898
- name: "as-of",
899
- description: "Point-in-time date (YYYY-MM-DD) for historical export.",
900
- type: "string"
901
- },
902
- {
903
- name: "show-empty-fields",
904
- description: "Include empty columns/rows in the export.",
905
- type: "boolean"
906
- }
907
- ]
908
- },
909
- {
910
- name: "register",
911
- group: "captable",
912
- description: "Generate shareholder register PDF.",
913
- usage: "captable-ai register [--as-of YYYY-MM-DD] [--json]",
914
- requiresAuth: true,
915
- requiresPortal: true,
916
- flags: [
917
- {
918
- name: "as-of",
919
- description: "Point-in-time date (YYYY-MM-DD) for historical register.",
920
- type: "string"
921
- }
922
- ]
923
- },
924
- {
925
- name: "commit",
926
- group: "captable",
927
- description: "Commit pending draft objects to the cap table. Use --dry-run to preview selected/final IDs without writing. Execution requires --objects with final IDs from preview, or --all. Exits with NOTHING_TO_COMMIT if no drafts exist.",
928
- usage: "captable-ai commit --dry-run [--objects id1,id2,...] [--json]\ncaptable-ai commit (--objects id1,id2,... | --all) [--json]",
929
- requiresAuth: true,
930
- requiresPortal: true,
931
- flags: [
932
- {
933
- name: "dry-run",
934
- description: "Preview selected/final IDs and dependency blockers without committing.",
935
- type: "boolean"
936
- },
937
- {
938
- name: "all",
939
- description: "Commit all pending drafts for the active company.",
940
- type: "boolean"
941
- },
942
- {
943
- name: "objects",
944
- description: "Comma-separated final object IDs to commit selectively. Use preview.applyObjectIds.",
945
- type: "string"
946
- }
947
- ]
948
- },
949
- {
950
- name: "documents upload",
951
- group: "captable",
952
- description: "Upload cap table documents. Computes SHA-256, calls prepare, uploads to S3 via presigned PUT, then confirms. Classification runs automatically after confirmation.",
953
- usage: "captable-ai documents upload <file...> [--json]",
954
- requiresAuth: true,
955
- requiresPortal: true
956
- },
957
- {
958
- name: "documents list",
959
- group: "captable",
960
- description: "List uploaded cap table documents with their processing status, classification, and dates.",
961
- usage: "captable-ai documents list [--status STATUS] [--limit N] [--cursor C] [--json]",
962
- requiresAuth: true,
963
- requiresPortal: true,
964
- flags: [
965
- {
966
- name: "status",
967
- description: "Filter by document status.",
968
- type: "string",
969
- enum: [
970
- "PENDING_UPLOAD",
971
- "NEW",
972
- "EXTRACTION",
973
- "OCF_EXTRACTION",
974
- "CLASSIFICATION",
975
- "CLASSIFIED",
976
- "CREATION",
977
- "VALIDATION",
978
- "FINALIZATION",
979
- "PROCESSED",
980
- "FAILED",
981
- "CANCELLED"
982
- ]
983
- },
984
- { name: "limit", description: "Page size (1-100, default 50).", type: "number" },
985
- { name: "cursor", description: "Pagination cursor.", type: "string" }
986
- ]
987
- },
988
- {
989
- name: "documents delete",
990
- group: "captable",
991
- description: "Delete an uploaded document and all associated artifacts (OCF object, captable_document, s3_asset, S3 file). Rejects if non-DOCUMENT OCF objects still reference the document.",
992
- usage: "captable-ai documents delete <s3AssetId> [--json]",
993
- requiresAuth: true,
994
- requiresPortal: true
995
- },
996
- {
997
- name: "documents download",
998
- group: "captable",
999
- description: "Get a presigned download URL for a cap table document's source file. Valid for 1 hour.",
1000
- usage: "captable-ai documents download <s3AssetId> [--json]",
1001
- requiresAuth: true,
1002
- requiresPortal: true
1003
- },
1004
- {
1005
- name: "documents trigger-extraction",
1006
- group: "captable",
1007
- description: "Trigger OCF extraction for classified documents. Sends them to the extraction queue for processing. Optionally filter to specific document IDs.",
1008
- usage: "captable-ai documents trigger-extraction [--s3-asset-ids ID1,ID2,...] [--json]",
1009
- requiresAuth: true,
1010
- requiresPortal: true,
1011
- flags: [
1012
- {
1013
- name: "s3-asset-ids",
1014
- description: "Comma-separated S3 asset IDs to filter to specific documents.",
1015
- type: "string"
1016
- }
1017
- ]
1018
- },
1019
- {
1020
- name: "documents cancel-extraction",
1021
- group: "captable",
1022
- description: "Cancel a stuck document extraction \u2014 marks it as FAILED and triggers validation for the remaining documents.",
1023
- usage: "captable-ai documents cancel-extraction <s3AssetId> [--json]",
1024
- requiresAuth: true,
1025
- requiresPortal: true
1026
- },
1027
- {
1028
- name: "documents restart-extraction",
1029
- group: "captable",
1030
- description: "Atomically restart extraction for stuck in-flight documents \u2014 cancels and re-enqueues them in order, routing each to the correct pipeline. Prefer this over cancel-extraction + trigger-extraction.",
1031
- usage: "captable-ai documents restart-extraction [--s3-asset-ids ID1,ID2,...] [--json]",
1032
- requiresAuth: true,
1033
- requiresPortal: true,
1034
- flags: [
1035
- {
1036
- name: "s3-asset-ids",
1037
- description: "Comma-separated S3 asset IDs to restart specific documents.",
1038
- type: "string"
1039
- }
1040
- ]
1041
- },
1042
- {
1043
- name: "documents processing-status",
1044
- group: "captable",
1045
- description: "Show per-document processing status, queue position, and health (processing | queued | stalled | failed | done). Health derives from the backend heartbeat.",
1046
- usage: "captable-ai documents processing-status [--s3-asset-ids ID1,ID2,...] [--json]",
1047
- requiresAuth: true,
1048
- requiresPortal: true,
1049
- flags: [
1050
- {
1051
- name: "s3-asset-ids",
1052
- description: "Comma-separated S3 asset IDs to filter to specific documents.",
1053
- type: "string"
1054
- }
1055
- ]
1056
- },
1057
- {
1058
- name: "documents classification-types",
1059
- group: "captable",
1060
- description: "List available document classification types.",
1061
- usage: "captable-ai documents classification-types [--json]",
1062
- requiresAuth: true,
1063
- requiresPortal: false
1064
- },
1065
- {
1066
- name: "documents classification-update",
1067
- group: "captable",
1068
- description: "Update a document's classification labels and optional date.",
1069
- usage: "captable-ai documents classification-update --s3-asset-id ID --classification TYPE1,TYPE2 [--date YYYY-MM-DD] [--json]",
1070
- requiresAuth: true,
1071
- requiresPortal: true,
1072
- flags: [
1073
- {
1074
- name: "s3-asset-id",
1075
- description: "S3 asset ID of the document to classify.",
1076
- type: "string"
1077
- },
1078
- {
1079
- name: "classification",
1080
- description: "Comma-separated classification types to assign.",
1081
- type: "string"
1082
- },
1083
- {
1084
- name: "date",
1085
- description: "Optional document date (YYYY-MM-DD).",
1086
- type: "string"
1087
- }
1088
- ]
1089
- },
1090
- {
1091
- name: "documents reprocess",
1092
- group: "captable",
1093
- description: "Reprocess a document through the extraction pipeline.",
1094
- usage: "captable-ai documents reprocess --s3-asset-id ID [--json]",
1095
- requiresAuth: true,
1096
- requiresPortal: true,
1097
- flags: [
1098
- {
1099
- name: "s3-asset-id",
1100
- description: "S3 asset ID of the document to reprocess.",
1101
- type: "string"
1102
- }
1103
- ]
1104
- },
1105
- {
1106
- name: "retrigger-validation",
1107
- group: "captable",
1108
- description: "Force-retrigger OCF validation for the active company, bypassing the pending-documents check. Use when validation appears stuck.",
1109
- usage: "captable-ai retrigger-validation [--json]",
1110
- requiresAuth: true,
1111
- requiresPortal: true
1112
- },
1113
- {
1114
- name: "pro-forma run",
1115
- group: "captable",
1116
- description: "Run a pro-forma cap table scenario: financing round, convertible conversion, warrant exercise, or option pool expansion.",
1117
- usage: "captable-ai pro-forma run <type> [flags] [--json]\n Types: financing, convertible, warrant, option-pool",
1118
- requiresAuth: true,
1119
- requiresPortal: true,
1120
- flags: [
1121
- { name: "pre-money", description: "Pre-money valuation (financing).", type: "number" },
1122
- { name: "amount", description: "Investment amount (financing).", type: "number" },
1123
- { name: "class-name", description: "New stock class name (financing).", type: "string" },
1124
- { name: "investor", description: "Lead investor name (financing).", type: "string" },
1125
- {
1126
- name: "pool-expansion",
1127
- description: "Target option pool % of post-money (financing).",
1128
- type: "number"
1129
- },
1130
- {
1131
- name: "pool-timing",
1132
- description: "PRE_MONEY or POST_MONEY (financing).",
1133
- type: "string",
1134
- enum: ["PRE_MONEY", "POST_MONEY"]
1135
- },
1136
- {
1137
- name: "trigger-valuation",
1138
- description: "Valuation triggering conversion (convertible).",
1139
- type: "number"
1140
- },
1141
- {
1142
- name: "include-interest",
1143
- description: "Include accrued interest for notes (convertible).",
1144
- type: "boolean"
1145
- },
1146
- { name: "exercise-all", description: "Exercise all warrants (warrant).", type: "boolean" },
1147
- {
1148
- name: "security-ids",
1149
- description: "Comma-separated security IDs (convertible, warrant).",
1150
- type: "string"
1151
- },
1152
- {
1153
- name: "target-percentage",
1154
- description: "Target pool % of fully diluted (option-pool).",
1155
- type: "number"
1156
- },
1157
- {
1158
- name: "additional-shares",
1159
- description: "Fixed shares to add (option-pool).",
1160
- type: "number"
1161
- }
1162
- ]
1163
- },
1164
- {
1165
- name: "jobs list",
1166
- group: "jobs",
1167
- description: "List tracked async jobs (extraction, validation) from the local job tracker.",
1168
- usage: "captable-ai jobs list [--status submitted|running|complete|failed] [--json]",
1169
- requiresAuth: false,
1170
- requiresPortal: false,
1171
- flags: [
1172
- {
1173
- name: "status",
1174
- description: "Filter by job status.",
1175
- type: "string",
1176
- enum: ["submitted", "running", "complete", "failed"]
1177
- }
1178
- ]
1179
- },
1180
- {
1181
- name: "jobs get",
1182
- group: "jobs",
1183
- description: "Check current status of a tracked job by polling the API and updating the local tracker.",
1184
- usage: "captable-ai jobs get <job-id> [--json]",
1185
- requiresAuth: true,
1186
- requiresPortal: false
1187
- },
1188
- {
1189
- name: "jobs prune",
1190
- group: "jobs",
1191
- description: "Remove completed/failed jobs older than 7 days (or --before date) from the local tracker.",
1192
- usage: "captable-ai jobs prune [--before YYYY-MM-DD] [--json]",
1193
- requiresAuth: false,
1194
- requiresPortal: false,
1195
- flags: [
1196
- {
1197
- name: "before",
1198
- description: "Remove jobs submitted before this date (YYYY-MM-DD).",
1199
- type: "string"
1200
- }
1201
- ]
1202
- },
1203
- {
1204
- name: "profile list",
1205
- group: "profile",
1206
- description: "List saved configuration profiles.",
1207
- usage: "captable-ai profile list [--json]",
1208
- requiresAuth: false,
1209
- requiresPortal: false
1210
- },
1211
- {
1212
- name: "profile get",
1213
- group: "profile",
1214
- description: "Show a profile's configuration.",
1215
- usage: "captable-ai profile get <name> [--json]",
1216
- requiresAuth: false,
1217
- requiresPortal: false
1218
- },
1219
- {
1220
- name: "profile save",
1221
- group: "profile",
1222
- description: "Create or update a named profile.",
1223
- usage: "captable-ai profile save <name> --company=<id> [--stage=<s>] [--json]",
1224
- requiresAuth: false,
1225
- requiresPortal: false,
1226
- flags: [
1227
- { name: "company", description: "Company (portal) ID for this profile.", type: "string" },
1228
- {
1229
- name: "stage",
1230
- description: "Stage override.",
1231
- type: "string",
1232
- enum: ["dev", "staging", "production", "local"]
1233
- }
1234
- ]
1235
- },
1236
- {
1237
- name: "profile delete",
1238
- group: "profile",
1239
- description: "Remove a saved profile.",
1240
- usage: "captable-ai profile delete <name> [--json]",
1241
- requiresAuth: false,
1242
- requiresPortal: false
1243
- },
1244
- {
1245
- name: "profile use",
1246
- group: "profile",
1247
- description: "Set a profile as the default.",
1248
- usage: "captable-ai profile use <name> [--json]",
1249
- requiresAuth: false,
1250
- requiresPortal: false
1251
- },
1252
- {
1253
- name: "feedback",
1254
- group: "feedback",
1255
- description: "Record CLI friction feedback locally.",
1256
- usage: 'captable-ai feedback "<message>" [--json]',
1257
- requiresAuth: false,
1258
- requiresPortal: false
1259
- },
1260
- {
1261
- name: "feedback list",
1262
- group: "feedback",
1263
- description: "List recorded feedback entries.",
1264
- usage: "captable-ai feedback list [--json]",
1265
- requiresAuth: false,
1266
- requiresPortal: false
1267
- },
1268
- {
1269
- name: "feedback send",
1270
- group: "feedback",
1271
- description: "POST unsent feedback to upstream endpoint (requires CAPTABLE_AI_FEEDBACK_URL).",
1272
- usage: "captable-ai feedback send [--json]",
1273
- requiresAuth: false,
1274
- requiresPortal: false
1275
- },
1276
- {
1277
- name: "logs list",
1278
- group: "logs",
1279
- description: "List OCF agent log entries (expert/validator runs) for the active portal. Requires Fairmint super-admin.",
1280
- usage: "captable-ai logs list [--agent-type expert|validator] [--limit N] [--cursor C] [--json]",
1281
- requiresAuth: true,
1282
- requiresPortal: true,
1283
- flags: [
1284
- {
1285
- name: "agent-type",
1286
- description: "Filter by agent type.",
1287
- type: "string",
1288
- enum: ["expert", "validator"]
1289
- },
1290
- { name: "limit", description: "Page size (1\u2013200, default 50).", type: "number" },
1291
- {
1292
- name: "cursor",
1293
- description: "Pagination cursor from a previous response.",
1294
- type: "string"
1295
- }
1296
- ]
1297
- },
1298
- {
1299
- name: "commands",
1300
- group: "commands",
1301
- description: "List all available commands (machine-readable JSON).",
1302
- usage: "captable-ai commands",
1303
- requiresAuth: false,
1304
- requiresPortal: false
1305
- }
1306
- ];
1307
- async function runCommands(_args) {
1308
- printJson({ schemaVersion: "10", version: "0.0.1", commands: COMMAND_REGISTRY });
1309
- }
1310
-
1311
451
  // ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/external.js
1312
452
  var external_exports = {};
1313
453
  __export(external_exports, {
@@ -15771,11 +14911,43 @@ var documentDownloadResultSchema = external_exports.object({
15771
14911
  contentType: external_exports.string().describe("MIME type."),
15772
14912
  expiresAt: external_exports.string().describe("URL expiry timestamp.")
15773
14913
  });
14914
+ var REGISTER_SECTION_OPTIONS = [
14915
+ {
14916
+ field: "includeShareClassDetails",
14917
+ flag: "include-share-class-details",
14918
+ description: "Include a Share Class Details section in the PDF."
14919
+ },
14920
+ {
14921
+ field: "includeTransactionHistory",
14922
+ flag: "include-transaction-history",
14923
+ description: "Include a Transaction History section in the PDF."
14924
+ },
14925
+ {
14926
+ field: "includeEquityAwards",
14927
+ flag: "include-equity-awards",
14928
+ description: "Include option grants and other equity awards: adds an Option Grants & Equity Awards section, includes equity-award events in Transaction History, and counts award-only holders in Number of Shareholders (Number of Record Holders stays stock-only). Set this when the user wants option or grant holders in the register."
14929
+ }
14930
+ ];
14931
+ var REGISTER_SECTION_DESCRIPTIONS = REGISTER_SECTION_OPTIONS.reduce((acc, option) => {
14932
+ acc[option.field] = option.description;
14933
+ return acc;
14934
+ }, {});
14935
+ function registerSectionField(field) {
14936
+ const description = REGISTER_SECTION_DESCRIPTIONS[field];
14937
+ if (description === void 0) {
14938
+ throw new Error(`Missing register section description for ${field}`);
14939
+ }
14940
+ return external_exports.boolean().optional().default(false).describe(description);
14941
+ }
14942
+ var registerSectionFields = {
14943
+ includeShareClassDetails: registerSectionField("includeShareClassDetails"),
14944
+ includeTransactionHistory: registerSectionField("includeTransactionHistory"),
14945
+ includeEquityAwards: registerSectionField("includeEquityAwards")
14946
+ };
15774
14947
  var generateRegisterInputSchema = external_exports.object({
15775
14948
  asOf: external_exports.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().describe("Point-in-time date for register (YYYY-MM-DD)."),
15776
14949
  reportType: external_exports.literal("shareholder_register").optional().default("shareholder_register").describe("Report type."),
15777
- includeShareClassDetails: external_exports.boolean().optional().default(false).describe("Include a Share Class Details section in the PDF."),
15778
- includeTransactionHistory: external_exports.boolean().optional().default(false).describe("Include a Transaction History section in the PDF.")
14950
+ ...registerSectionFields
15779
14951
  });
15780
14952
  var generateRegisterResultSchema = external_exports.object({
15781
14953
  downloadUrl: external_exports.string().describe("Presigned S3 download URL for the PDF."),
@@ -17257,154 +16429,1065 @@ async function apiRequest(path, opts = {}) {
17257
16429
  } catch (refreshErr) {
17258
16430
  exitForRefreshFailure(refreshErr, softFail);
17259
16431
  }
17260
- if (refreshed) {
17261
- headers.Authorization = `Bearer ${refreshed.accessToken}`;
17262
- try {
17263
- const retryRes = await fetch(url2.toString(), buildFetchOpts());
17264
- return handleResponse(retryRes, softFail);
17265
- } catch (retryErr) {
17266
- if (retryErr instanceof DOMException && retryErr.name === "TimeoutError") {
17267
- failRequest(
17268
- softFail,
17269
- "Request timed out. Check your network connection and try again.",
17270
- "TIMEOUT",
17271
- void 0,
17272
- EXIT.NETWORK
17273
- );
17274
- }
17275
- failRequest(
17276
- softFail,
17277
- `Network error: ${retryErr instanceof Error ? retryErr.message : "connection failed"}`,
17278
- "NETWORK",
17279
- void 0,
17280
- EXIT.NETWORK
17281
- );
17282
- }
16432
+ if (refreshed) {
16433
+ headers.Authorization = `Bearer ${refreshed.accessToken}`;
16434
+ try {
16435
+ const retryRes = await fetch(url2.toString(), buildFetchOpts());
16436
+ return handleResponse(retryRes, softFail);
16437
+ } catch (retryErr) {
16438
+ if (retryErr instanceof DOMException && retryErr.name === "TimeoutError") {
16439
+ failRequest(
16440
+ softFail,
16441
+ "Request timed out. Check your network connection and try again.",
16442
+ "TIMEOUT",
16443
+ void 0,
16444
+ EXIT.NETWORK
16445
+ );
16446
+ }
16447
+ failRequest(
16448
+ softFail,
16449
+ `Network error: ${retryErr instanceof Error ? retryErr.message : "connection failed"}`,
16450
+ "NETWORK",
16451
+ void 0,
16452
+ EXIT.NETWORK
16453
+ );
16454
+ }
16455
+ }
16456
+ }
16457
+ }
16458
+ return handleResponse(res, softFail);
16459
+ }
16460
+ function exitCodeForStatus(status) {
16461
+ if (status === 400) return EXIT.VALIDATION;
16462
+ if (status === 401 || status === 403) return EXIT.AUTH;
16463
+ if (status === 404) return EXIT.NOT_FOUND;
16464
+ if (status === 409) return EXIT.CONFLICT;
16465
+ if (status === 422) return EXIT.VALIDATION;
16466
+ if (status >= 500) return EXIT.SERVER_ERROR;
16467
+ return EXIT.SERVER_ERROR;
16468
+ }
16469
+ async function handleResponse(res, softFail = false) {
16470
+ let text;
16471
+ try {
16472
+ text = await res.text();
16473
+ } catch (err) {
16474
+ failRequest(
16475
+ softFail,
16476
+ `Network error: ${err instanceof Error ? err.message : "connection failed"}`,
16477
+ "NETWORK",
16478
+ void 0,
16479
+ EXIT.NETWORK
16480
+ );
16481
+ }
16482
+ let parsed;
16483
+ try {
16484
+ parsed = JSON.parse(text);
16485
+ } catch {
16486
+ if (!res.ok) {
16487
+ failRequest(
16488
+ softFail,
16489
+ `HTTP ${res.status}: ${text.slice(0, 200)}`,
16490
+ `HTTP_${res.status}`,
16491
+ void 0,
16492
+ exitCodeForStatus(res.status)
16493
+ );
16494
+ }
16495
+ return { data: text };
16496
+ }
16497
+ if (!res.ok) {
16498
+ const exitCode = exitCodeForStatus(res.status);
16499
+ const obj = isRecord2(parsed) ? parsed : {};
16500
+ const nested = obj.error;
16501
+ if (isRecord2(nested)) {
16502
+ const code = typeof nested.code === "string" && nested.code.trim() ? nested.code : void 0;
16503
+ const details = coerceDetails(nested.details);
16504
+ failRequest(
16505
+ softFail,
16506
+ String(nested.message ?? `HTTP ${res.status}`),
16507
+ code,
16508
+ details,
16509
+ exitCode
16510
+ );
16511
+ }
16512
+ if (typeof nested === "string") {
16513
+ const code = typeof obj.code === "string" && obj.code.trim() ? obj.code : `HTTP_${res.status}`;
16514
+ const details = coerceDetails(obj.details);
16515
+ failRequest(softFail, nested, code, details, exitCode);
16516
+ }
16517
+ failRequest(
16518
+ softFail,
16519
+ `HTTP ${res.status}: ${text.slice(0, 200)}`,
16520
+ void 0,
16521
+ void 0,
16522
+ exitCode
16523
+ );
16524
+ }
16525
+ return parsed;
16526
+ }
16527
+
16528
+ // src/flags.ts
16529
+ function looksLikeFlag(value) {
16530
+ if (!value.startsWith("-")) return false;
16531
+ if (value === "-" || /^-\d+(?:\.\d+)?$/.test(value)) return false;
16532
+ return true;
16533
+ }
16534
+ function parseArgs(argv) {
16535
+ const positional = [];
16536
+ const positionalIndexes = [];
16537
+ const flags = {};
16538
+ const flagValueSources = {};
16539
+ const flagValueIndexes = {};
16540
+ const boolean4 = /* @__PURE__ */ new Set();
16541
+ let i = 0;
16542
+ while (i < argv.length) {
16543
+ const arg = argv[i];
16544
+ if (arg.startsWith("--")) {
16545
+ const eqIdx = arg.indexOf("=");
16546
+ if (eqIdx !== -1) {
16547
+ const key = arg.slice(2, eqIdx);
16548
+ flags[key] = arg.slice(eqIdx + 1);
16549
+ flagValueSources[key] = "equals";
16550
+ flagValueIndexes[key] = i;
16551
+ } else {
16552
+ const key = arg.slice(2);
16553
+ const next = argv[i + 1];
16554
+ if (next !== void 0 && !looksLikeFlag(next)) {
16555
+ flags[key] = next;
16556
+ flagValueSources[key] = "next";
16557
+ flagValueIndexes[key] = i + 1;
16558
+ i++;
16559
+ } else {
16560
+ boolean4.add(key);
16561
+ }
16562
+ }
16563
+ } else {
16564
+ positional.push(arg);
16565
+ positionalIndexes.push(i);
16566
+ }
16567
+ i++;
16568
+ }
16569
+ return { positional, positionalIndexes, flags, flagValueSources, flagValueIndexes, boolean: boolean4 };
16570
+ }
16571
+ function hasFlag(args, name) {
16572
+ return args.boolean.has(name) || name in args.flags;
16573
+ }
16574
+ function getFlagValue(args, name) {
16575
+ return args.flags[name];
16576
+ }
16577
+ function argvRequestsHelp(argv) {
16578
+ if (argv.includes("--help") || argv.includes("-h")) return true;
16579
+ return argv[0] === "help";
16580
+ }
16581
+
16582
+ // src/commands/register.ts
16583
+ var REGISTER_USAGE = `captable-ai register [--as-of YYYY-MM-DD] ${REGISTER_SECTION_OPTIONS.map((o) => `[--${o.flag}]`).join(" ")} [--json]`;
16584
+ async function runRegister(args) {
16585
+ validateFlags(args, {
16586
+ flags: ["as-of"],
16587
+ booleans: REGISTER_SECTION_OPTIONS.map((option) => option.flag)
16588
+ });
16589
+ if (args.positional.length > 0) {
16590
+ exitWithUsage(
16591
+ `Unexpected argument: ${args.positional[0]}. This command takes no positional arguments; section flags take no value (omit a flag to leave that section off).`,
16592
+ REGISTER_USAGE
16593
+ );
16594
+ }
16595
+ const portalId = await getActivePortalId();
16596
+ const asOf = getFlagValue(args, "as-of");
16597
+ const body = {};
16598
+ if (asOf) body.asOf = asOf;
16599
+ for (const option of REGISTER_SECTION_OPTIONS) {
16600
+ if (hasFlag(args, option.flag)) body[option.field] = true;
16601
+ }
16602
+ const res = await apiRequest(`/${portalId}/register`, {
16603
+ method: "POST",
16604
+ body
16605
+ });
16606
+ if (isJsonMode()) {
16607
+ printJson({ data: res.data });
16608
+ return;
16609
+ }
16610
+ const d = res.data;
16611
+ if (!d) {
16612
+ exitWithError(
16613
+ "Register generation failed \u2014 no data returned.",
16614
+ "ERROR",
16615
+ void 0,
16616
+ EXIT.SERVER_ERROR
16617
+ );
16618
+ }
16619
+ printLine("\n Shareholder register generated successfully.\n");
16620
+ printKeyValue([
16621
+ ["Download URL", d.downloadUrl],
16622
+ ["Filename", d.filename],
16623
+ ["Expires at", d.expiresAt]
16624
+ ]);
16625
+ printLine();
16626
+ }
16627
+
16628
+ // src/commands/commands.ts
16629
+ var COMMAND_REGISTRY = [
16630
+ {
16631
+ name: "login",
16632
+ group: "auth",
16633
+ description: "Authenticate via browser-based login.",
16634
+ usage: "captable-ai login",
16635
+ requiresAuth: false,
16636
+ requiresPortal: false
16637
+ },
16638
+ {
16639
+ name: "logout",
16640
+ group: "auth",
16641
+ description: "Revoke tokens and clear local credentials.",
16642
+ usage: "captable-ai logout",
16643
+ requiresAuth: false,
16644
+ requiresPortal: false
16645
+ },
16646
+ {
16647
+ name: "auth status",
16648
+ group: "auth",
16649
+ description: "Show authentication status, token expiry, and active company.",
16650
+ usage: "captable-ai auth status",
16651
+ requiresAuth: false,
16652
+ requiresPortal: false
16653
+ },
16654
+ {
16655
+ name: "company list",
16656
+ group: "company",
16657
+ description: "List available companies.",
16658
+ usage: "captable-ai company list",
16659
+ requiresAuth: true,
16660
+ requiresPortal: false
16661
+ },
16662
+ {
16663
+ name: "company use",
16664
+ group: "company",
16665
+ description: "Set the active company by ID or name.",
16666
+ usage: "captable-ai company use <id-or-name>",
16667
+ requiresAuth: true,
16668
+ requiresPortal: false
16669
+ },
16670
+ {
16671
+ name: "company current",
16672
+ group: "company",
16673
+ description: "Show the active company.",
16674
+ usage: "captable-ai company current",
16675
+ requiresAuth: true,
16676
+ requiresPortal: false
16677
+ },
16678
+ {
16679
+ name: "company create",
16680
+ group: "company",
16681
+ description: "Create a new test portal with ISSUER OCF object. Requires Fairmint super admin.",
16682
+ usage: "captable-ai company create --name <company-name> [--legal-name <name>] [--domain <domain>] [--country <code>] [--formation-date <YYYY-MM-DD>] [--currency <code>] [--json]",
16683
+ requiresAuth: true,
16684
+ requiresPortal: false,
16685
+ flags: [
16686
+ { name: "name", description: "Company display name (required).", type: "string" },
16687
+ {
16688
+ name: "legal-name",
16689
+ description: "Legal entity name (defaults to --name).",
16690
+ type: "string"
16691
+ },
16692
+ { name: "domain", description: "Portal domain.", type: "string" },
16693
+ { name: "country", description: "ISO 3166-1 alpha-2 country code.", type: "string" },
16694
+ { name: "formation-date", description: "Incorporation date (YYYY-MM-DD).", type: "string" },
16695
+ { name: "currency", description: "Currency ISO 4217 (default: USD).", type: "string" }
16696
+ ]
16697
+ },
16698
+ {
16699
+ name: "company delete",
16700
+ group: "company",
16701
+ description: "Delete a test portal and all child data. Dev-only. Requires Fairmint super admin.",
16702
+ usage: "captable-ai company delete <company-id> [--yes] [--json]",
16703
+ requiresAuth: true,
16704
+ requiresPortal: false,
16705
+ flags: [{ name: "yes", description: "Skip the confirmation prompt.", type: "boolean" }]
16706
+ },
16707
+ {
16708
+ name: "onboarding status",
16709
+ group: "onboarding",
16710
+ description: "Show the next first-workspace or import action. Works for authenticated users with zero companies.",
16711
+ usage: "captable-ai onboarding status [--session <import-session-id>] [--json]",
16712
+ requiresAuth: true,
16713
+ requiresPortal: false,
16714
+ flags: [
16715
+ {
16716
+ name: "session",
16717
+ description: "Inspect this import session instead of local workspace state.",
16718
+ type: "string"
16719
+ }
16720
+ ]
16721
+ },
16722
+ {
16723
+ name: "onboarding setup",
16724
+ group: "onboarding",
16725
+ description: "Idempotently create the authenticated user's first production workspace. Only --accept-terms is required; the company profile is read from uploaded documents.",
16726
+ usage: "captable-ai onboarding setup --accept-terms [--legal-name <name>] [--company-type <type>] [--country <code>] [--role <role>] [--other-role <role>] [--cap-table-source <source>] [--other-cap-table-source <source>] [--stakeholder-count <bucket>] [--json]",
16727
+ requiresAuth: true,
16728
+ requiresPortal: false,
16729
+ flags: [
16730
+ {
16731
+ name: "accept-terms",
16732
+ description: "Confirm acceptance of Fairmint's Terms of Service (required).",
16733
+ type: "boolean"
16734
+ },
16735
+ {
16736
+ name: "legal-name",
16737
+ description: "Company name. Left unset until you or document extraction supplies one.",
16738
+ type: "string"
16739
+ },
16740
+ {
16741
+ name: "company-type",
16742
+ description: "Legal entity type. Left unrecorded when omitted.",
16743
+ type: "string",
16744
+ enum: ["us_c_corporation", "us_llc", "foreign_entity", "not_incorporated"]
16745
+ },
16746
+ {
16747
+ name: "country",
16748
+ description: "ISO 3166-1 alpha-2 code. Only with --company-type foreign_entity.",
16749
+ type: "string"
16750
+ },
16751
+ {
16752
+ name: "role",
16753
+ description: "Your role at the company.",
16754
+ type: "string",
16755
+ enum: [
16756
+ "CEO",
16757
+ "COO",
16758
+ "CMO",
16759
+ "CFO",
16760
+ "CTO",
16761
+ "CRO",
16762
+ "Director",
16763
+ "Founder",
16764
+ "co-founder",
16765
+ "co-CEO",
16766
+ "other"
16767
+ ]
16768
+ },
16769
+ {
16770
+ name: "other-role",
16771
+ description: "Free-text role. Required when --role other.",
16772
+ type: "string"
16773
+ },
16774
+ {
16775
+ name: "cap-table-source",
16776
+ description: "Where the cap table is maintained today.",
16777
+ type: "string",
16778
+ enum: ["none", "spreadsheet", "carta", "pulley", "angellist", "other"]
16779
+ },
16780
+ {
16781
+ name: "other-cap-table-source",
16782
+ description: "Free-text source. Required when --cap-table-source other.",
16783
+ type: "string"
16784
+ },
16785
+ {
16786
+ name: "stakeholder-count",
16787
+ description: "Approximate number of stakeholders on the cap table.",
16788
+ type: "string",
16789
+ enum: ["1_10", "11_25", "26_50", "50_100", "100_plus"]
16790
+ }
16791
+ ]
16792
+ },
16793
+ {
16794
+ name: "import start",
16795
+ group: "onboarding",
16796
+ description: "Start or reuse a secure import session for existing document upload APIs.",
16797
+ usage: "captable-ai import start [--json]",
16798
+ requiresAuth: true,
16799
+ requiresPortal: true
16800
+ },
16801
+ {
16802
+ name: "import status",
16803
+ group: "onboarding",
16804
+ description: "Show import processing progress and the next existing-pipeline action.",
16805
+ usage: "captable-ai import status <session-id> [--json]",
16806
+ requiresAuth: true,
16807
+ requiresPortal: false
16808
+ },
16809
+ {
16810
+ name: "summary",
16811
+ group: "captable",
16812
+ description: "Full cap table snapshot: capitalization, stakeholders, convertibles, metrics, and status.",
16813
+ usage: "captable-ai summary [--as-of YYYY-MM-DD] [--include-pending] [--skip-stakeholders] [--page overview] [--json]",
16814
+ requiresAuth: true,
16815
+ requiresPortal: true,
16816
+ flags: [
16817
+ {
16818
+ name: "as-of",
16819
+ description: "Historical snapshot date (YYYY-MM-DD).",
16820
+ type: "string"
16821
+ },
16822
+ {
16823
+ name: "include-pending",
16824
+ description: "Include draft objects in computation.",
16825
+ type: "boolean"
16826
+ },
16827
+ {
16828
+ name: "skip-stakeholders",
16829
+ description: "Omit stakeholderView section (faster).",
16830
+ type: "boolean"
16831
+ },
16832
+ {
16833
+ name: "page",
16834
+ description: "Use 'overview' for lightweight issuer/metrics/status.",
16835
+ type: "string",
16836
+ enum: ["overview"]
16837
+ }
16838
+ ]
16839
+ },
16840
+ {
16841
+ name: "objects list",
16842
+ group: "captable",
16843
+ description: "List OCF objects with filtering and pagination.",
16844
+ usage: "captable-ai objects list [--type TYPE] [--subtype SUBTYPE] [--status STATUS] [--limit N] [--cursor C] [--q QUERY] [--from YYYY-MM-DD] [--to YYYY-MM-DD] [--ids IDS] [--stakeholder ID] [--document ID] [--all] [--max-confidence N] [--json]",
16845
+ requiresAuth: true,
16846
+ requiresPortal: true,
16847
+ flags: [
16848
+ {
16849
+ name: "type",
16850
+ description: "Filter by top-level OCF type (comma-separated). Use `schemas list` for allowed values.",
16851
+ type: "string"
16852
+ },
16853
+ {
16854
+ name: "subtype",
16855
+ description: "Filter by TRANSACTION subtype (comma-separated). Use `schemas get TRANSACTION` for allowed values.",
16856
+ type: "string"
16857
+ },
16858
+ {
16859
+ name: "status",
16860
+ description: "Filter by status: draft or committed.",
16861
+ type: "string",
16862
+ enum: ["draft", "committed"]
16863
+ },
16864
+ { name: "limit", description: "Page size (1-250, default 100).", type: "number" },
16865
+ { name: "cursor", description: "Pagination cursor.", type: "string" },
16866
+ { name: "q", description: "Full-text search query.", type: "string" },
16867
+ {
16868
+ name: "from",
16869
+ description: "Filter objects with date >= (YYYY-MM-DD, inclusive).",
16870
+ type: "string"
16871
+ },
16872
+ {
16873
+ name: "to",
16874
+ description: "Filter objects with date <= (YYYY-MM-DD, inclusive).",
16875
+ type: "string"
16876
+ },
16877
+ { name: "ids", description: "Batch fetch by comma-separated IDs.", type: "string" },
16878
+ {
16879
+ name: "stakeholder",
16880
+ description: "Filter by OCF stakeholder id.",
16881
+ type: "string"
16882
+ },
16883
+ {
16884
+ name: "document",
16885
+ description: "Filter by source document s3 asset id.",
16886
+ type: "string"
16887
+ },
16888
+ {
16889
+ name: "all",
16890
+ description: "Follow pagination cursors until every matching object is returned.",
16891
+ type: "boolean"
16892
+ },
16893
+ {
16894
+ name: "max-confidence",
16895
+ description: "Keep objects with extraction confidence <= N. Requires --all.",
16896
+ type: "number"
16897
+ }
16898
+ ]
16899
+ },
16900
+ {
16901
+ name: "objects review-non-cash",
16902
+ group: "captable",
16903
+ description: "List unmarked convertible issuances whose stored evidence suggests possible non-cash consideration.",
16904
+ usage: "captable-ai objects review-non-cash [--status draft|committed] [--json]",
16905
+ requiresAuth: true,
16906
+ requiresPortal: true,
16907
+ flags: [
16908
+ {
16909
+ name: "status",
16910
+ description: "Review only latest draft or committed objects.",
16911
+ type: "string",
16912
+ enum: ["draft", "committed"]
16913
+ }
16914
+ ]
16915
+ },
16916
+ {
16917
+ name: "objects get",
16918
+ group: "captable",
16919
+ description: "Get a single OCF object with document, extraction details, and a vesting summary when present.",
16920
+ usage: "captable-ai objects get <object-id> [--json]",
16921
+ requiresAuth: true,
16922
+ requiresPortal: true
16923
+ },
16924
+ {
16925
+ name: "objects dump",
16926
+ group: "captable",
16927
+ description: "Write engine-shaped ocf.json from object ocf payloads.",
16928
+ usage: "captable-ai objects dump [--status committed|draft] [--output path]",
16929
+ requiresAuth: true,
16930
+ requiresPortal: true,
16931
+ flags: [
16932
+ {
16933
+ name: "status",
16934
+ description: "Filter by status: draft or committed. Default committed.",
16935
+ type: "string",
16936
+ enum: ["draft", "committed"]
16937
+ },
16938
+ {
16939
+ name: "output",
16940
+ description: "Write JSON to this file (global --output; implies --json).",
16941
+ type: "string"
16942
+ }
16943
+ ]
16944
+ },
16945
+ {
16946
+ name: "schemas list",
16947
+ group: "captable",
16948
+ description: "List available OCF object types.",
16949
+ usage: "captable-ai schemas list [--json]",
16950
+ requiresAuth: true,
16951
+ requiresPortal: false
16952
+ },
16953
+ {
16954
+ name: "schemas get",
16955
+ group: "captable",
16956
+ description: "Get the schema for an OCF object type.",
16957
+ usage: "captable-ai schemas get <object-type> [--json]",
16958
+ requiresAuth: true,
16959
+ requiresPortal: false
16960
+ },
16961
+ {
16962
+ name: "objects update",
16963
+ group: "captable",
16964
+ description: "Update an OCF object (committed or draft) by uploading a complete OCF payload (version-checked). Supply the payload via --stdin (piped JSON) or --file <path>. The --version is auto-fetched from the server if omitted.",
16965
+ usage: "captable-ai objects update <object-id> (--stdin | --file <path>) [--version N] [--json]",
16966
+ requiresAuth: true,
16967
+ requiresPortal: true,
16968
+ flags: [
16969
+ { name: "stdin", description: "Read complete OCF JSON payload from stdin.", type: "boolean" },
16970
+ {
16971
+ name: "file",
16972
+ description: "Path to a JSON file containing the complete OCF payload.",
16973
+ type: "string"
16974
+ },
16975
+ {
16976
+ name: "version",
16977
+ description: "Optimistic-concurrency version number. Auto-fetched from objects get if omitted.",
16978
+ type: "number"
16979
+ }
16980
+ ]
16981
+ },
16982
+ {
16983
+ name: "objects patch",
16984
+ group: "captable",
16985
+ description: "Patch an OCF object by uploading a partial OCF payload. The server shallow-merges the patch, validates the merged result, and writes a draft.",
16986
+ usage: "captable-ai objects patch <object-id> (--stdin | --file <path>) [--version N] [--json]",
16987
+ requiresAuth: true,
16988
+ requiresPortal: true,
16989
+ flags: [
16990
+ { name: "stdin", description: "Read partial OCF JSON payload from stdin.", type: "boolean" },
16991
+ {
16992
+ name: "file",
16993
+ description: "Path to a JSON file containing the partial OCF payload.",
16994
+ type: "string"
16995
+ },
16996
+ {
16997
+ name: "version",
16998
+ description: "Optional optimistic-concurrency version number.",
16999
+ type: "number"
17000
+ }
17001
+ ]
17002
+ },
17003
+ {
17004
+ name: "objects revert",
17005
+ group: "captable",
17006
+ description: "Preview or revert draft objects using backend dependency closure. Execution requires explicit final IDs (<object-id> or --objects) or --all.",
17007
+ usage: "captable-ai objects revert --dry-run [<object-id> | --objects id1,id2,... | --all] [--json]\ncaptable-ai objects revert (<object-id> | --objects id1,id2,... | --all) [--yes] [--json]",
17008
+ requiresAuth: true,
17009
+ requiresPortal: true,
17010
+ flags: [
17011
+ {
17012
+ name: "dry-run",
17013
+ description: "Preview selected/final IDs and dependency blockers without writing.",
17014
+ type: "boolean"
17015
+ },
17016
+ {
17017
+ name: "objects",
17018
+ description: "Comma-separated final object IDs to revert selectively.",
17019
+ type: "string"
17020
+ },
17021
+ {
17022
+ name: "all",
17023
+ description: "Revert all pending drafts for the active company.",
17024
+ type: "boolean"
17025
+ },
17026
+ {
17027
+ name: "yes",
17028
+ description: "Skip the confirmation prompt when using --all.",
17029
+ type: "boolean"
17030
+ }
17031
+ ]
17032
+ },
17033
+ {
17034
+ name: "objects delete",
17035
+ group: "captable",
17036
+ description: "Permanently delete an OCF object. By default deletes only the latest version; use --delete-all to remove all versions. Supports --expected-version for concurrency.",
17037
+ usage: "captable-ai objects delete <objectId> [--delete-all] [--expected-version N] [--yes] [--json]",
17038
+ requiresAuth: true,
17039
+ requiresPortal: true,
17040
+ flags: [
17041
+ {
17042
+ name: "delete-all",
17043
+ description: "Delete all versions, not just the latest.",
17044
+ type: "boolean"
17045
+ },
17046
+ {
17047
+ name: "expected-version",
17048
+ description: "Expected version for optimistic concurrency check.",
17049
+ type: "number"
17050
+ },
17051
+ {
17052
+ name: "yes",
17053
+ description: "Skip the confirmation prompt.",
17054
+ type: "boolean"
17055
+ }
17056
+ ]
17057
+ },
17058
+ {
17059
+ name: "objects versions",
17060
+ group: "captable",
17061
+ description: "List versions of an OCF object (draft vs committed).",
17062
+ usage: "captable-ai objects versions <object-id> [--json]",
17063
+ requiresAuth: true,
17064
+ requiresPortal: true
17065
+ },
17066
+ {
17067
+ name: "export",
17068
+ group: "captable",
17069
+ description: "Export the cap table as an Excel workbook. Returns a presigned download URL valid for 1 hour.",
17070
+ usage: "captable-ai export [--as-of YYYY-MM-DD] [--show-empty-fields] [--json]",
17071
+ requiresAuth: true,
17072
+ requiresPortal: true,
17073
+ flags: [
17074
+ {
17075
+ name: "as-of",
17076
+ description: "Point-in-time date (YYYY-MM-DD) for historical export.",
17077
+ type: "string"
17078
+ },
17079
+ {
17080
+ name: "show-empty-fields",
17081
+ description: "Include empty columns/rows in the export.",
17082
+ type: "boolean"
17083
+ }
17084
+ ]
17085
+ },
17086
+ {
17087
+ name: "register",
17088
+ group: "captable",
17089
+ description: "Generate a shareholder register PDF (shareholders of record by default). Returns a presigned download URL.",
17090
+ usage: REGISTER_USAGE,
17091
+ requiresAuth: true,
17092
+ requiresPortal: true,
17093
+ flags: [
17094
+ {
17095
+ name: "as-of",
17096
+ description: "Point-in-time date (YYYY-MM-DD) for historical register.",
17097
+ type: "string"
17098
+ },
17099
+ ...REGISTER_SECTION_OPTIONS.map((option) => ({
17100
+ name: option.flag,
17101
+ description: option.description,
17102
+ type: "boolean"
17103
+ }))
17104
+ ]
17105
+ },
17106
+ {
17107
+ name: "commit",
17108
+ group: "captable",
17109
+ description: "Commit pending draft objects to the cap table. Use --dry-run to preview selected/final IDs without writing. Execution requires --objects with final IDs from preview, or --all. Exits with NOTHING_TO_COMMIT if no drafts exist.",
17110
+ usage: "captable-ai commit --dry-run [--objects id1,id2,...] [--json]\ncaptable-ai commit (--objects id1,id2,... | --all) [--json]",
17111
+ requiresAuth: true,
17112
+ requiresPortal: true,
17113
+ flags: [
17114
+ {
17115
+ name: "dry-run",
17116
+ description: "Preview selected/final IDs and dependency blockers without committing.",
17117
+ type: "boolean"
17118
+ },
17119
+ {
17120
+ name: "all",
17121
+ description: "Commit all pending drafts for the active company.",
17122
+ type: "boolean"
17123
+ },
17124
+ {
17125
+ name: "objects",
17126
+ description: "Comma-separated final object IDs to commit selectively. Use preview.applyObjectIds.",
17127
+ type: "string"
17128
+ }
17129
+ ]
17130
+ },
17131
+ {
17132
+ name: "documents upload",
17133
+ group: "captable",
17134
+ description: "Upload cap table documents. Computes SHA-256, calls prepare, uploads to S3 via presigned PUT, then confirms. Classification runs automatically after confirmation.",
17135
+ usage: "captable-ai documents upload <file...> [--json]",
17136
+ requiresAuth: true,
17137
+ requiresPortal: true
17138
+ },
17139
+ {
17140
+ name: "documents list",
17141
+ group: "captable",
17142
+ description: "List uploaded cap table documents with their processing status, classification, and dates.",
17143
+ usage: "captable-ai documents list [--status STATUS] [--limit N] [--cursor C] [--json]",
17144
+ requiresAuth: true,
17145
+ requiresPortal: true,
17146
+ flags: [
17147
+ {
17148
+ name: "status",
17149
+ description: "Filter by document status.",
17150
+ type: "string",
17151
+ enum: [
17152
+ "PENDING_UPLOAD",
17153
+ "NEW",
17154
+ "EXTRACTION",
17155
+ "OCF_EXTRACTION",
17156
+ "CLASSIFICATION",
17157
+ "CLASSIFIED",
17158
+ "CREATION",
17159
+ "VALIDATION",
17160
+ "FINALIZATION",
17161
+ "PROCESSED",
17162
+ "FAILED",
17163
+ "CANCELLED"
17164
+ ]
17165
+ },
17166
+ { name: "limit", description: "Page size (1-100, default 50).", type: "number" },
17167
+ { name: "cursor", description: "Pagination cursor.", type: "string" }
17168
+ ]
17169
+ },
17170
+ {
17171
+ name: "documents delete",
17172
+ group: "captable",
17173
+ description: "Delete an uploaded document and all associated artifacts (OCF object, captable_document, s3_asset, S3 file). Rejects if non-DOCUMENT OCF objects still reference the document.",
17174
+ usage: "captable-ai documents delete <s3AssetId> [--json]",
17175
+ requiresAuth: true,
17176
+ requiresPortal: true
17177
+ },
17178
+ {
17179
+ name: "documents download",
17180
+ group: "captable",
17181
+ description: "Get a presigned download URL for a cap table document's source file. Valid for 1 hour.",
17182
+ usage: "captable-ai documents download <s3AssetId> [--json]",
17183
+ requiresAuth: true,
17184
+ requiresPortal: true
17185
+ },
17186
+ {
17187
+ name: "documents trigger-extraction",
17188
+ group: "captable",
17189
+ description: "Trigger OCF extraction for classified documents. Sends them to the extraction queue for processing. Optionally filter to specific document IDs.",
17190
+ usage: "captable-ai documents trigger-extraction [--s3-asset-ids ID1,ID2,...] [--json]",
17191
+ requiresAuth: true,
17192
+ requiresPortal: true,
17193
+ flags: [
17194
+ {
17195
+ name: "s3-asset-ids",
17196
+ description: "Comma-separated S3 asset IDs to filter to specific documents.",
17197
+ type: "string"
17198
+ }
17199
+ ]
17200
+ },
17201
+ {
17202
+ name: "documents cancel-extraction",
17203
+ group: "captable",
17204
+ description: "Cancel a stuck document extraction \u2014 marks it as FAILED and triggers validation for the remaining documents.",
17205
+ usage: "captable-ai documents cancel-extraction <s3AssetId> [--json]",
17206
+ requiresAuth: true,
17207
+ requiresPortal: true
17208
+ },
17209
+ {
17210
+ name: "documents restart-extraction",
17211
+ group: "captable",
17212
+ description: "Atomically restart extraction for stuck in-flight documents \u2014 cancels and re-enqueues them in order, routing each to the correct pipeline. Prefer this over cancel-extraction + trigger-extraction.",
17213
+ usage: "captable-ai documents restart-extraction [--s3-asset-ids ID1,ID2,...] [--json]",
17214
+ requiresAuth: true,
17215
+ requiresPortal: true,
17216
+ flags: [
17217
+ {
17218
+ name: "s3-asset-ids",
17219
+ description: "Comma-separated S3 asset IDs to restart specific documents.",
17220
+ type: "string"
17221
+ }
17222
+ ]
17223
+ },
17224
+ {
17225
+ name: "documents processing-status",
17226
+ group: "captable",
17227
+ description: "Show per-document processing status, queue position, and health (processing | queued | stalled | failed | done). Health derives from the backend heartbeat.",
17228
+ usage: "captable-ai documents processing-status [--s3-asset-ids ID1,ID2,...] [--json]",
17229
+ requiresAuth: true,
17230
+ requiresPortal: true,
17231
+ flags: [
17232
+ {
17233
+ name: "s3-asset-ids",
17234
+ description: "Comma-separated S3 asset IDs to filter to specific documents.",
17235
+ type: "string"
17236
+ }
17237
+ ]
17238
+ },
17239
+ {
17240
+ name: "documents classification-types",
17241
+ group: "captable",
17242
+ description: "List available document classification types.",
17243
+ usage: "captable-ai documents classification-types [--json]",
17244
+ requiresAuth: true,
17245
+ requiresPortal: false
17246
+ },
17247
+ {
17248
+ name: "documents classification-update",
17249
+ group: "captable",
17250
+ description: "Update a document's classification labels and optional date.",
17251
+ usage: "captable-ai documents classification-update --s3-asset-id ID --classification TYPE1,TYPE2 [--date YYYY-MM-DD] [--json]",
17252
+ requiresAuth: true,
17253
+ requiresPortal: true,
17254
+ flags: [
17255
+ {
17256
+ name: "s3-asset-id",
17257
+ description: "S3 asset ID of the document to classify.",
17258
+ type: "string"
17259
+ },
17260
+ {
17261
+ name: "classification",
17262
+ description: "Comma-separated classification types to assign.",
17263
+ type: "string"
17264
+ },
17265
+ {
17266
+ name: "date",
17267
+ description: "Optional document date (YYYY-MM-DD).",
17268
+ type: "string"
17269
+ }
17270
+ ]
17271
+ },
17272
+ {
17273
+ name: "documents reprocess",
17274
+ group: "captable",
17275
+ description: "Reprocess a document through the extraction pipeline.",
17276
+ usage: "captable-ai documents reprocess --s3-asset-id ID [--json]",
17277
+ requiresAuth: true,
17278
+ requiresPortal: true,
17279
+ flags: [
17280
+ {
17281
+ name: "s3-asset-id",
17282
+ description: "S3 asset ID of the document to reprocess.",
17283
+ type: "string"
17284
+ }
17285
+ ]
17286
+ },
17287
+ {
17288
+ name: "retrigger-validation",
17289
+ group: "captable",
17290
+ description: "Force-retrigger OCF validation for the active company, bypassing the pending-documents check. Use when validation appears stuck.",
17291
+ usage: "captable-ai retrigger-validation [--json]",
17292
+ requiresAuth: true,
17293
+ requiresPortal: true
17294
+ },
17295
+ {
17296
+ name: "pro-forma run",
17297
+ group: "captable",
17298
+ description: "Run a pro-forma cap table scenario: financing round, convertible conversion, warrant exercise, or option pool expansion.",
17299
+ usage: "captable-ai pro-forma run <type> [flags] [--json]\n Types: financing, convertible, warrant, option-pool",
17300
+ requiresAuth: true,
17301
+ requiresPortal: true,
17302
+ flags: [
17303
+ { name: "pre-money", description: "Pre-money valuation (financing).", type: "number" },
17304
+ { name: "amount", description: "Investment amount (financing).", type: "number" },
17305
+ { name: "class-name", description: "New stock class name (financing).", type: "string" },
17306
+ { name: "investor", description: "Lead investor name (financing).", type: "string" },
17307
+ {
17308
+ name: "pool-expansion",
17309
+ description: "Target option pool % of post-money (financing).",
17310
+ type: "number"
17311
+ },
17312
+ {
17313
+ name: "pool-timing",
17314
+ description: "PRE_MONEY or POST_MONEY (financing).",
17315
+ type: "string",
17316
+ enum: ["PRE_MONEY", "POST_MONEY"]
17317
+ },
17318
+ {
17319
+ name: "trigger-valuation",
17320
+ description: "Valuation triggering conversion (convertible).",
17321
+ type: "number"
17322
+ },
17323
+ {
17324
+ name: "include-interest",
17325
+ description: "Include accrued interest for notes (convertible).",
17326
+ type: "boolean"
17327
+ },
17328
+ { name: "exercise-all", description: "Exercise all warrants (warrant).", type: "boolean" },
17329
+ {
17330
+ name: "security-ids",
17331
+ description: "Comma-separated security IDs (convertible, warrant).",
17332
+ type: "string"
17333
+ },
17334
+ {
17335
+ name: "target-percentage",
17336
+ description: "Target pool % of fully diluted (option-pool).",
17337
+ type: "number"
17338
+ },
17339
+ {
17340
+ name: "additional-shares",
17341
+ description: "Fixed shares to add (option-pool).",
17342
+ type: "number"
17343
+ }
17344
+ ]
17345
+ },
17346
+ {
17347
+ name: "jobs list",
17348
+ group: "jobs",
17349
+ description: "List tracked async jobs (extraction, validation) from the local job tracker.",
17350
+ usage: "captable-ai jobs list [--status submitted|running|complete|failed] [--json]",
17351
+ requiresAuth: false,
17352
+ requiresPortal: false,
17353
+ flags: [
17354
+ {
17355
+ name: "status",
17356
+ description: "Filter by job status.",
17357
+ type: "string",
17358
+ enum: ["submitted", "running", "complete", "failed"]
17359
+ }
17360
+ ]
17361
+ },
17362
+ {
17363
+ name: "jobs get",
17364
+ group: "jobs",
17365
+ description: "Check current status of a tracked job by polling the API and updating the local tracker.",
17366
+ usage: "captable-ai jobs get <job-id> [--json]",
17367
+ requiresAuth: true,
17368
+ requiresPortal: false
17369
+ },
17370
+ {
17371
+ name: "jobs prune",
17372
+ group: "jobs",
17373
+ description: "Remove completed/failed jobs older than 7 days (or --before date) from the local tracker.",
17374
+ usage: "captable-ai jobs prune [--before YYYY-MM-DD] [--json]",
17375
+ requiresAuth: false,
17376
+ requiresPortal: false,
17377
+ flags: [
17378
+ {
17379
+ name: "before",
17380
+ description: "Remove jobs submitted before this date (YYYY-MM-DD).",
17381
+ type: "string"
17382
+ }
17383
+ ]
17384
+ },
17385
+ {
17386
+ name: "profile list",
17387
+ group: "profile",
17388
+ description: "List saved configuration profiles.",
17389
+ usage: "captable-ai profile list [--json]",
17390
+ requiresAuth: false,
17391
+ requiresPortal: false
17392
+ },
17393
+ {
17394
+ name: "profile get",
17395
+ group: "profile",
17396
+ description: "Show a profile's configuration.",
17397
+ usage: "captable-ai profile get <name> [--json]",
17398
+ requiresAuth: false,
17399
+ requiresPortal: false
17400
+ },
17401
+ {
17402
+ name: "profile save",
17403
+ group: "profile",
17404
+ description: "Create or update a named profile.",
17405
+ usage: "captable-ai profile save <name> --company=<id> [--stage=<s>] [--json]",
17406
+ requiresAuth: false,
17407
+ requiresPortal: false,
17408
+ flags: [
17409
+ { name: "company", description: "Company (portal) ID for this profile.", type: "string" },
17410
+ {
17411
+ name: "stage",
17412
+ description: "Stage override.",
17413
+ type: "string",
17414
+ enum: ["dev", "staging", "production", "local"]
17283
17415
  }
17284
- }
17285
- }
17286
- return handleResponse(res, softFail);
17287
- }
17288
- function exitCodeForStatus(status) {
17289
- if (status === 400) return EXIT.VALIDATION;
17290
- if (status === 401 || status === 403) return EXIT.AUTH;
17291
- if (status === 404) return EXIT.NOT_FOUND;
17292
- if (status === 409) return EXIT.CONFLICT;
17293
- if (status === 422) return EXIT.VALIDATION;
17294
- if (status >= 500) return EXIT.SERVER_ERROR;
17295
- return EXIT.SERVER_ERROR;
17296
- }
17297
- async function handleResponse(res, softFail = false) {
17298
- let text;
17299
- try {
17300
- text = await res.text();
17301
- } catch (err) {
17302
- failRequest(
17303
- softFail,
17304
- `Network error: ${err instanceof Error ? err.message : "connection failed"}`,
17305
- "NETWORK",
17306
- void 0,
17307
- EXIT.NETWORK
17308
- );
17309
- }
17310
- let parsed;
17311
- try {
17312
- parsed = JSON.parse(text);
17313
- } catch {
17314
- if (!res.ok) {
17315
- failRequest(
17316
- softFail,
17317
- `HTTP ${res.status}: ${text.slice(0, 200)}`,
17318
- `HTTP_${res.status}`,
17319
- void 0,
17320
- exitCodeForStatus(res.status)
17321
- );
17322
- }
17323
- return { data: text };
17324
- }
17325
- if (!res.ok) {
17326
- const exitCode = exitCodeForStatus(res.status);
17327
- const obj = isRecord2(parsed) ? parsed : {};
17328
- const nested = obj.error;
17329
- if (isRecord2(nested)) {
17330
- const code = typeof nested.code === "string" && nested.code.trim() ? nested.code : void 0;
17331
- const details = coerceDetails(nested.details);
17332
- failRequest(
17333
- softFail,
17334
- String(nested.message ?? `HTTP ${res.status}`),
17335
- code,
17336
- details,
17337
- exitCode
17338
- );
17339
- }
17340
- if (typeof nested === "string") {
17341
- const code = typeof obj.code === "string" && obj.code.trim() ? obj.code : `HTTP_${res.status}`;
17342
- const details = coerceDetails(obj.details);
17343
- failRequest(softFail, nested, code, details, exitCode);
17344
- }
17345
- failRequest(
17346
- softFail,
17347
- `HTTP ${res.status}: ${text.slice(0, 200)}`,
17348
- void 0,
17349
- void 0,
17350
- exitCode
17351
- );
17352
- }
17353
- return parsed;
17354
- }
17355
-
17356
- // src/flags.ts
17357
- function looksLikeFlag(value) {
17358
- if (!value.startsWith("-")) return false;
17359
- if (value === "-" || /^-\d+(?:\.\d+)?$/.test(value)) return false;
17360
- return true;
17361
- }
17362
- function parseArgs(argv) {
17363
- const positional = [];
17364
- const positionalIndexes = [];
17365
- const flags = {};
17366
- const flagValueSources = {};
17367
- const flagValueIndexes = {};
17368
- const boolean4 = /* @__PURE__ */ new Set();
17369
- let i = 0;
17370
- while (i < argv.length) {
17371
- const arg = argv[i];
17372
- if (arg.startsWith("--")) {
17373
- const eqIdx = arg.indexOf("=");
17374
- if (eqIdx !== -1) {
17375
- const key = arg.slice(2, eqIdx);
17376
- flags[key] = arg.slice(eqIdx + 1);
17377
- flagValueSources[key] = "equals";
17378
- flagValueIndexes[key] = i;
17379
- } else {
17380
- const key = arg.slice(2);
17381
- const next = argv[i + 1];
17382
- if (next !== void 0 && !looksLikeFlag(next)) {
17383
- flags[key] = next;
17384
- flagValueSources[key] = "next";
17385
- flagValueIndexes[key] = i + 1;
17386
- i++;
17387
- } else {
17388
- boolean4.add(key);
17389
- }
17416
+ ]
17417
+ },
17418
+ {
17419
+ name: "profile delete",
17420
+ group: "profile",
17421
+ description: "Remove a saved profile.",
17422
+ usage: "captable-ai profile delete <name> [--json]",
17423
+ requiresAuth: false,
17424
+ requiresPortal: false
17425
+ },
17426
+ {
17427
+ name: "profile use",
17428
+ group: "profile",
17429
+ description: "Set a profile as the default.",
17430
+ usage: "captable-ai profile use <name> [--json]",
17431
+ requiresAuth: false,
17432
+ requiresPortal: false
17433
+ },
17434
+ {
17435
+ name: "feedback",
17436
+ group: "feedback",
17437
+ description: "Record CLI friction feedback locally.",
17438
+ usage: 'captable-ai feedback "<message>" [--json]',
17439
+ requiresAuth: false,
17440
+ requiresPortal: false
17441
+ },
17442
+ {
17443
+ name: "feedback list",
17444
+ group: "feedback",
17445
+ description: "List recorded feedback entries.",
17446
+ usage: "captable-ai feedback list [--json]",
17447
+ requiresAuth: false,
17448
+ requiresPortal: false
17449
+ },
17450
+ {
17451
+ name: "feedback send",
17452
+ group: "feedback",
17453
+ description: "POST unsent feedback to upstream endpoint (requires CAPTABLE_AI_FEEDBACK_URL).",
17454
+ usage: "captable-ai feedback send [--json]",
17455
+ requiresAuth: false,
17456
+ requiresPortal: false
17457
+ },
17458
+ {
17459
+ name: "logs list",
17460
+ group: "logs",
17461
+ description: "List OCF agent log entries (expert/validator runs) for the active portal. Requires Fairmint super-admin.",
17462
+ usage: "captable-ai logs list [--agent-type expert|validator] [--limit N] [--cursor C] [--json]",
17463
+ requiresAuth: true,
17464
+ requiresPortal: true,
17465
+ flags: [
17466
+ {
17467
+ name: "agent-type",
17468
+ description: "Filter by agent type.",
17469
+ type: "string",
17470
+ enum: ["expert", "validator"]
17471
+ },
17472
+ { name: "limit", description: "Page size (1\u2013200, default 50).", type: "number" },
17473
+ {
17474
+ name: "cursor",
17475
+ description: "Pagination cursor from a previous response.",
17476
+ type: "string"
17390
17477
  }
17391
- } else {
17392
- positional.push(arg);
17393
- positionalIndexes.push(i);
17394
- }
17395
- i++;
17478
+ ]
17479
+ },
17480
+ {
17481
+ name: "commands",
17482
+ group: "commands",
17483
+ description: "List all available commands (machine-readable JSON).",
17484
+ usage: "captable-ai commands",
17485
+ requiresAuth: false,
17486
+ requiresPortal: false
17396
17487
  }
17397
- return { positional, positionalIndexes, flags, flagValueSources, flagValueIndexes, boolean: boolean4 };
17398
- }
17399
- function hasFlag(args, name) {
17400
- return args.boolean.has(name) || name in args.flags;
17401
- }
17402
- function getFlagValue(args, name) {
17403
- return args.flags[name];
17404
- }
17405
- function argvRequestsHelp(argv) {
17406
- if (argv.includes("--help") || argv.includes("-h")) return true;
17407
- return argv[0] === "help";
17488
+ ];
17489
+ async function runCommands(_args) {
17490
+ printJson({ schemaVersion: "10", version: "0.0.1", commands: COMMAND_REGISTRY });
17408
17491
  }
17409
17492
 
17410
17493
  // src/help-text.ts
@@ -17866,16 +17949,25 @@ Options:
17866
17949
  Global:
17867
17950
  --json Machine-readable JSON output
17868
17951
  --output <path> Write JSON response to file (implies --json)`;
17869
- var HELP_REGISTER = `register \u2014 Generate shareholder register PDF (not yet available)
17952
+ var HELP_REGISTER = `register \u2014 Generate shareholder register PDF
17870
17953
 
17871
17954
  Usage:
17872
- captable-ai register [--as-of YYYY-MM-DD] [--json]
17955
+ captable-ai register [--as-of YYYY-MM-DD] [--include-share-class-details]
17956
+ [--include-transaction-history] [--include-equity-awards] [--json]
17873
17957
 
17874
- NOTE: This endpoint is not yet implemented (returns 501). The PDF engine
17875
- (pdfmake) needs to be ported from the legacy API.
17958
+ Returns a presigned S3 download URL for the PDF. By default the register lists
17959
+ shareholders of record only (stock holdings); each optional section is off
17960
+ unless its flag is passed.
17876
17961
 
17877
17962
  Options:
17878
- --as-of YYYY-MM-DD Historical snapshot date (YYYY-MM-DD)
17963
+ --as-of YYYY-MM-DD Historical snapshot date (YYYY-MM-DD)
17964
+ --include-share-class-details Add a Share Class Details section
17965
+ --include-transaction-history Add a Transaction History section
17966
+ --include-equity-awards Add option grants and other equity awards: an
17967
+ Option Grants & Equity Awards section, award
17968
+ events in transaction history, and award-only
17969
+ holders in Number of Shareholders. Number of
17970
+ Record Holders stays stock-only.
17879
17971
 
17880
17972
  Global:
17881
17973
  --json Machine-readable JSON output
@@ -21882,42 +21974,6 @@ async function runProfileUse(args) {
21882
21974
  printSuccess(`Default profile set to "${name}".`);
21883
21975
  }
21884
21976
 
21885
- // src/commands/register.ts
21886
- async function runRegister(args) {
21887
- validateFlags(args, {
21888
- flags: ["as-of"],
21889
- booleans: []
21890
- });
21891
- const portalId = await getActivePortalId();
21892
- const asOf = getFlagValue(args, "as-of");
21893
- const body = {};
21894
- if (asOf) body.asOf = asOf;
21895
- const res = await apiRequest(`/${portalId}/register`, {
21896
- method: "POST",
21897
- body
21898
- });
21899
- if (isJsonMode()) {
21900
- printJson({ data: res.data });
21901
- return;
21902
- }
21903
- const d = res.data;
21904
- if (!d) {
21905
- exitWithError(
21906
- "Register generation failed \u2014 no data returned.",
21907
- "ERROR",
21908
- void 0,
21909
- EXIT.SERVER_ERROR
21910
- );
21911
- }
21912
- printLine("\n Shareholder register generated successfully.\n");
21913
- printKeyValue([
21914
- ["Download URL", d.downloadUrl],
21915
- ["Filename", d.filename],
21916
- ["Expires at", d.expiresAt]
21917
- ]);
21918
- printLine();
21919
- }
21920
-
21921
21977
  // src/commands/retrigger-validation.ts
21922
21978
  async function runRetriggerValidation(args) {
21923
21979
  validateFlags(args, { flags: [], booleans: [] });
@@ -22327,7 +22383,8 @@ Export:
22327
22383
 
22328
22384
  Reports:
22329
22385
  register Generate shareholder register PDF
22330
- Options: --as-of YYYY-MM-DD
22386
+ Options: --as-of YYYY-MM-DD, --include-share-class-details,
22387
+ --include-transaction-history, --include-equity-awards
22331
22388
 
22332
22389
  Pro-Forma:
22333
22390
  pro-forma run <type> Model a scenario (financing, convertible, warrant, option-pool)