@fairmint/captable-ai 0.1.10 → 0.1.12

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 (2) hide show
  1. package/dist/index.js +181 -2
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -599,6 +599,22 @@ var COMMAND_REGISTRY = [
599
599
  }
600
600
  ]
601
601
  },
602
+ {
603
+ name: "objects review-non-cash",
604
+ group: "captable",
605
+ description: "List unmarked convertible issuances whose stored evidence suggests possible non-cash consideration.",
606
+ usage: "captable-ai objects review-non-cash [--status draft|committed] [--json]",
607
+ requiresAuth: true,
608
+ requiresPortal: true,
609
+ flags: [
610
+ {
611
+ name: "status",
612
+ description: "Review only latest draft or committed objects.",
613
+ type: "string",
614
+ enum: ["draft", "committed"]
615
+ }
616
+ ]
617
+ },
602
618
  {
603
619
  name: "objects get",
604
620
  group: "captable",
@@ -16575,7 +16591,10 @@ var warrantResolutionItemSchema = external_exports.object({
16575
16591
  amount: external_exports.string(),
16576
16592
  currency: external_exports.string()
16577
16593
  }).nullable(),
16578
- relatedSecurityId: external_exports.string().nullable()
16594
+ relatedSecurityId: external_exports.string().nullable(),
16595
+ // Present only on warrants whose deferred percentage exercise could not be replayed. They
16596
+ // are listed but excluded from the counts below, since they contribute no diluted shares.
16597
+ replayFailed: external_exports.boolean().optional()
16579
16598
  });
16580
16599
  var warrantsSnapshotSchema = external_exports.object({
16581
16600
  numberOfSecurities: external_exports.number().int().nonnegative(),
@@ -17029,6 +17048,27 @@ Human table sorts lowest extraction confidence first. Conf markers:
17029
17048
 
17030
17049
  Global:
17031
17050
  --json Machine-readable JSON output (API order, not confidence-sorted)`;
17051
+ var HELP_OBJECTS_REVIEW_NON_CASH = `objects review-non-cash \u2014 Review possible unclassified non-cash convertibles
17052
+
17053
+ Builds a read-only, portal-wide review queue from unmarked convertible issuances
17054
+ whose stored consideration text, comments, or source-document name mentions
17055
+ services or other possible non-cash consideration. Matches are evidence for human
17056
+ review only: this command never classifies, patches, or commits an OCF object.
17057
+
17058
+ Usage:
17059
+ captable-ai objects review-non-cash [--status draft|committed] [--json]
17060
+
17061
+ Options:
17062
+ --status STATUS Review only latest draft or committed objects
17063
+
17064
+ Workflow:
17065
+ 1. Run with --status committed --json and review each source agreement.
17066
+ 2. For confirmed wholly non-cash issuances, patch only consideration_text with
17067
+ NON_CASH: <document-verbatim description> using the reported object version.
17068
+ 3. Dry-run and commit exactly the reviewed object IDs together.
17069
+
17070
+ Global:
17071
+ --json Machine-readable output including evidence and object version`;
17032
17072
  var HELP_OBJECTS_GET = `objects get \u2014 Show one OCF object
17033
17073
 
17034
17074
  After the OCF payload, prints a one-line vesting summary when the object (or
@@ -17146,6 +17186,8 @@ var HELP_OBJECTS_GROUP = `objects \u2014 OCF objects
17146
17186
 
17147
17187
  ${HELP_OBJECTS_LIST}
17148
17188
 
17189
+ ${HELP_OBJECTS_REVIEW_NON_CASH}
17190
+
17149
17191
  ${HELP_OBJECTS_GET}
17150
17192
 
17151
17193
  ${HELP_OBJECTS_DUMP}
@@ -20167,6 +20209,136 @@ Reverted ${res.data.revertedCount} draft object(s).
20167
20209
  `);
20168
20210
  }
20169
20211
 
20212
+ // src/commands/objects-review-non-cash.ts
20213
+ var NON_CASH_PREFIX = "NON_CASH:";
20214
+ var POSSIBLE_NON_CASH_TERMS = /\b(?:non[- ]cash|services?|consulting|advisory|advisor|intellectual property|ip assignment|debt forgiveness|in[- ]kind)\b/i;
20215
+ function stringValue(value) {
20216
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
20217
+ }
20218
+ function collectCommentText(value) {
20219
+ if (typeof value === "string") return value.trim() ? [value.trim()] : [];
20220
+ if (!Array.isArray(value)) return [];
20221
+ return value.flatMap((comment) => {
20222
+ if (typeof comment === "string") return comment.trim() ? [comment.trim()] : [];
20223
+ if (!comment || typeof comment !== "object") return [];
20224
+ const text = Reflect.get(comment, "text") ?? Reflect.get(comment, "comment");
20225
+ return typeof text === "string" && text.trim() ? [text.trim()] : [];
20226
+ });
20227
+ }
20228
+ function hasValidNonCashMarker(considerationText) {
20229
+ if (typeof considerationText !== "string") return false;
20230
+ const trimmed = considerationText.trimStart();
20231
+ if (!trimmed.startsWith(NON_CASH_PREFIX)) return false;
20232
+ return trimmed.slice(NON_CASH_PREFIX.length).trim().length > 0;
20233
+ }
20234
+ function findNonCashReviewCandidates(objects, documents) {
20235
+ const documentsById = new Map(documents.map((document) => [document.id, document]));
20236
+ const candidates = [];
20237
+ for (const object2 of objects) {
20238
+ if (object2.subtype !== "TX_CONVERTIBLE_ISSUANCE") continue;
20239
+ if (hasValidNonCashMarker(object2.ocf.consideration_text)) continue;
20240
+ const evidence = [];
20241
+ const considerationText = stringValue(object2.ocf.consideration_text);
20242
+ if (considerationText && (considerationText.startsWith(NON_CASH_PREFIX) || POSSIBLE_NON_CASH_TERMS.test(considerationText))) {
20243
+ evidence.push({ field: "consideration_text", text: considerationText });
20244
+ }
20245
+ for (const comment of collectCommentText(object2.ocf.comments)) {
20246
+ if (POSSIBLE_NON_CASH_TERMS.test(comment)) {
20247
+ evidence.push({ field: "comments", text: comment });
20248
+ }
20249
+ }
20250
+ const document = object2.documentId ? documentsById.get(object2.documentId) : void 0;
20251
+ if (document && POSSIBLE_NON_CASH_TERMS.test(document.name)) {
20252
+ evidence.push({ field: "document", text: document.name });
20253
+ }
20254
+ if (evidence.length === 0) continue;
20255
+ candidates.push({
20256
+ objectId: object2.id,
20257
+ version: object2.version,
20258
+ status: object2.status,
20259
+ securityId: stringValue(object2.ocf.security_id),
20260
+ customId: stringValue(object2.ocf.custom_id),
20261
+ investmentAmount: object2.ocf.investment_amount ?? null,
20262
+ considerationText,
20263
+ documentId: object2.documentId ?? null,
20264
+ documentName: document?.name ?? null,
20265
+ evidence
20266
+ });
20267
+ }
20268
+ return candidates.sort((left, right) => left.objectId.localeCompare(right.objectId));
20269
+ }
20270
+ async function runObjectsReviewNonCash(args, rawArgv) {
20271
+ if (argvRequestsHelp(rawArgv)) {
20272
+ process.stdout.write(`${HELP_OBJECTS_REVIEW_NON_CASH}
20273
+ `);
20274
+ process.exit(0);
20275
+ }
20276
+ validateFlags(args, { flags: ["status"] });
20277
+ if (args.positional.length > 0) {
20278
+ exitWithError(
20279
+ `Unexpected argument: ${args.positional[0]}. This command takes no positional arguments.`,
20280
+ "UNEXPECTED_ARGUMENT",
20281
+ void 0,
20282
+ EXIT.USAGE
20283
+ );
20284
+ }
20285
+ const status = getFlagValue(args, "status");
20286
+ if (status !== void 0 && status !== "draft" && status !== "committed") {
20287
+ exitWithError(
20288
+ `--status must be one of: draft, committed (got: "${status}")`,
20289
+ "VALIDATION_FAILED",
20290
+ void 0,
20291
+ EXIT.VALIDATION
20292
+ );
20293
+ }
20294
+ const portalId = await getActivePortalId();
20295
+ const page = await fetchAllObjectPages(portalId, {
20296
+ subtype: "TX_CONVERTIBLE_ISSUANCE",
20297
+ status
20298
+ });
20299
+ const candidates = findNonCashReviewCandidates(page.data.objects, page.data.documents);
20300
+ if (isJsonMode()) {
20301
+ printJson({
20302
+ data: {
20303
+ candidates,
20304
+ reviewedCount: page.data.objects.length
20305
+ },
20306
+ meta: {
20307
+ candidateCount: candidates.length,
20308
+ classification: "human_review_required"
20309
+ }
20310
+ });
20311
+ return;
20312
+ }
20313
+ printLine(
20314
+ `
20315
+ Possible unclassified non-cash convertible consideration (${candidates.length} found):
20316
+ `
20317
+ );
20318
+ printTable(
20319
+ candidates.map((candidate) => ({
20320
+ id: candidate.objectId,
20321
+ version: candidate.version,
20322
+ security: candidate.customId ?? candidate.securityId ?? "",
20323
+ amount: candidate.investmentAmount && typeof candidate.investmentAmount === "object" ? Reflect.get(candidate.investmentAmount, "amount") ?? "" : "",
20324
+ document: candidate.documentName ?? candidate.documentId ?? "",
20325
+ evidence: candidate.evidence.map((item) => item.field).join(", ")
20326
+ })),
20327
+ [
20328
+ { key: "id", label: "Object ID", width: 38 },
20329
+ { key: "version", label: "Version", width: 8 },
20330
+ { key: "security", label: "Security", width: 18 },
20331
+ { key: "amount", label: "Amount", width: 12 },
20332
+ { key: "document", label: "Document", width: 24 },
20333
+ { key: "evidence", label: "Evidence", width: 28 }
20334
+ ]
20335
+ );
20336
+ printLine(
20337
+ "\nReview the source agreement before patching. This command never classifies or writes objects."
20338
+ );
20339
+ printLine();
20340
+ }
20341
+
20170
20342
  // src/commands/objects-update.ts
20171
20343
  import { readFileSync as readFileSync2 } from "fs";
20172
20344
  async function readStdin2() {
@@ -21257,6 +21429,7 @@ Cap Table (read):
21257
21429
  Review: --stakeholder, --document, --max-confidence N (requires --all)
21258
21430
  Pagination: --limit (1-250), --cursor, --all
21259
21431
  Dates: --from / --to as YYYY-MM-DD
21432
+ objects review-non-cash Find unmarked convertibles that need consideration review
21260
21433
  objects get <id> Show a single OCF object (vesting summary when present)
21261
21434
  objects dump Engine-shaped ocf.json (default --status committed; --output path)
21262
21435
  schemas list List OCF object types
@@ -21554,6 +21727,12 @@ async function main() {
21554
21727
  case "patch":
21555
21728
  await runObjectsPatch(parseArgs(positionalArgs.slice(2)), positionalArgs.slice(2));
21556
21729
  break;
21730
+ case "review-non-cash":
21731
+ await runObjectsReviewNonCash(
21732
+ parseArgs(positionalArgs.slice(2)),
21733
+ positionalArgs.slice(2)
21734
+ );
21735
+ break;
21557
21736
  case "revert":
21558
21737
  await runObjectsRevert(parseArgs(positionalArgs.slice(2)), positionalArgs.slice(2));
21559
21738
  break;
@@ -21565,7 +21744,7 @@ async function main() {
21565
21744
  break;
21566
21745
  default:
21567
21746
  exitWithError(
21568
- `Unknown objects command: ${sub ?? "(none)"}. Try: objects list | get | dump | update | patch | revert | versions | delete`,
21747
+ `Unknown objects command: ${sub ?? "(none)"}. Try: objects list | review-non-cash | get | dump | update | patch | revert | versions | delete`,
21569
21748
  "UNKNOWN_COMMAND",
21570
21749
  void 0,
21571
21750
  EXIT.USAGE
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fairmint/captable-ai",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "Agent-native CLI for Captable AI — manage companies, upload documents, run OCF extraction, and commit cap tables from the terminal.",
5
5
  "keywords": [
6
6
  "captable",