@fairmint/captable-ai 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.js +401 -77
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -88,7 +88,7 @@ automated, but a few habits make extraction faster and more accurate:
|
|
|
88
88
|
| `documents upload\|list\|download\|delete` | Manage source documents |
|
|
89
89
|
| `documents trigger-extraction\|cancel-extraction\|restart-extraction\|reprocess` | Control the OCF extraction pipeline |
|
|
90
90
|
| `documents processing-status\|classification-types\|classification-update` | Inspect document status / classification |
|
|
91
|
-
| `objects list\|get\|update\|patch\|revert\|versions\|delete` | Work with extracted OCF objects (`list` supports `--document`, `--stakeholder`, `--all`, `--max-confidence`) |
|
|
91
|
+
| `objects list\|get\|dump\|update\|patch\|revert\|versions\|delete` | Work with extracted OCF objects (`list` supports `--document`, `--stakeholder`, `--all`, `--max-confidence`; `dump` writes engine-shaped `ocf.json`) |
|
|
92
92
|
| `schemas list\|get` | Browse the OCF object-type registry |
|
|
93
93
|
| `commit` | Commit drafts to the cap table — `--all` or `--objects id1,id2` (`--dry-run` to preview) |
|
|
94
94
|
| `summary` | Full cap table snapshot |
|
package/dist/index.js
CHANGED
|
@@ -607,6 +607,27 @@ var COMMAND_REGISTRY = [
|
|
|
607
607
|
requiresAuth: true,
|
|
608
608
|
requiresPortal: true
|
|
609
609
|
},
|
|
610
|
+
{
|
|
611
|
+
name: "objects dump",
|
|
612
|
+
group: "captable",
|
|
613
|
+
description: "Write engine-shaped ocf.json from object ocf payloads.",
|
|
614
|
+
usage: "captable-ai objects dump [--status committed|draft] [--output path]",
|
|
615
|
+
requiresAuth: true,
|
|
616
|
+
requiresPortal: true,
|
|
617
|
+
flags: [
|
|
618
|
+
{
|
|
619
|
+
name: "status",
|
|
620
|
+
description: "Filter by status: draft or committed. Default committed.",
|
|
621
|
+
type: "string",
|
|
622
|
+
enum: ["draft", "committed"]
|
|
623
|
+
},
|
|
624
|
+
{
|
|
625
|
+
name: "output",
|
|
626
|
+
description: "Write JSON to this file (global --output; implies --json).",
|
|
627
|
+
type: "string"
|
|
628
|
+
}
|
|
629
|
+
]
|
|
630
|
+
},
|
|
610
631
|
{
|
|
611
632
|
name: "schemas list",
|
|
612
633
|
group: "captable",
|
|
@@ -1147,7 +1168,7 @@ var COMMAND_REGISTRY = [
|
|
|
1147
1168
|
}
|
|
1148
1169
|
];
|
|
1149
1170
|
async function runCommands(_args) {
|
|
1150
|
-
printJson({ schemaVersion: "
|
|
1171
|
+
printJson({ schemaVersion: "8", version: "0.0.1", commands: COMMAND_REGISTRY });
|
|
1151
1172
|
}
|
|
1152
1173
|
|
|
1153
1174
|
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/external.js
|
|
@@ -16043,6 +16064,235 @@ var exportResultSchema = external_exports.object({
|
|
|
16043
16064
|
}).optional().describe("Present when pro-forma sheets were requested but engine refused.")
|
|
16044
16065
|
});
|
|
16045
16066
|
|
|
16067
|
+
// ../captable-ai-core/dist/objects-dump.js
|
|
16068
|
+
var DumpAssemblyError = class extends Error {
|
|
16069
|
+
constructor(message) {
|
|
16070
|
+
super(message);
|
|
16071
|
+
this.name = "DumpAssemblyError";
|
|
16072
|
+
}
|
|
16073
|
+
};
|
|
16074
|
+
var ISSUANCE_TYPES = /* @__PURE__ */ new Set([
|
|
16075
|
+
"TX_STOCK_ISSUANCE",
|
|
16076
|
+
"TX_CONVERTIBLE_ISSUANCE",
|
|
16077
|
+
"TX_WARRANT_ISSUANCE",
|
|
16078
|
+
"TX_EQUITY_COMPENSATION_ISSUANCE",
|
|
16079
|
+
"TX_PLAN_SECURITY_ISSUANCE"
|
|
16080
|
+
]);
|
|
16081
|
+
var CONVERSION_PARENT_TYPES = /* @__PURE__ */ new Set([
|
|
16082
|
+
"TX_CONVERTIBLE_CONVERSION",
|
|
16083
|
+
"TX_WARRANT_EXERCISE",
|
|
16084
|
+
"TX_EQUITY_COMPENSATION_EXERCISE",
|
|
16085
|
+
"TX_EQUITY_COMPENSATION_RELEASE",
|
|
16086
|
+
"TX_PLAN_SECURITY_RELEASE",
|
|
16087
|
+
"TX_STOCK_TRANSFER",
|
|
16088
|
+
"TX_STOCK_CONVERSION",
|
|
16089
|
+
"TX_CONVERTIBLE_TRANSFER",
|
|
16090
|
+
"TX_WARRANT_TRANSFER",
|
|
16091
|
+
"TX_EQUITY_COMPENSATION_TRANSFER",
|
|
16092
|
+
"TX_PLAN_SECURITY_TRANSFER",
|
|
16093
|
+
"TX_STOCK_REISSUANCE"
|
|
16094
|
+
]);
|
|
16095
|
+
function isRecord(value) {
|
|
16096
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16097
|
+
}
|
|
16098
|
+
function canonicalType(obj) {
|
|
16099
|
+
const type = String(obj.type ?? "").toUpperCase();
|
|
16100
|
+
if (type === "OBJECT")
|
|
16101
|
+
return String(obj.subtype ?? "").toUpperCase();
|
|
16102
|
+
return type;
|
|
16103
|
+
}
|
|
16104
|
+
function issuerForEngine(payload) {
|
|
16105
|
+
if (payload.initial_shares_authorized == null && payload.authorized_shares != null) {
|
|
16106
|
+
return { ...payload, initial_shares_authorized: payload.authorized_shares };
|
|
16107
|
+
}
|
|
16108
|
+
return payload;
|
|
16109
|
+
}
|
|
16110
|
+
function payloadId(payload, fallback) {
|
|
16111
|
+
return typeof payload.id === "string" && payload.id.length > 0 ? payload.id : fallback;
|
|
16112
|
+
}
|
|
16113
|
+
function pushByOcfId(bucket, payload, fallback) {
|
|
16114
|
+
bucket.set(payloadId(payload, fallback), payload);
|
|
16115
|
+
}
|
|
16116
|
+
function timestampMs(input, defaultValue) {
|
|
16117
|
+
if (input == null)
|
|
16118
|
+
return defaultValue;
|
|
16119
|
+
const ms = typeof input === "number" ? input : new Date(String(input)).getTime();
|
|
16120
|
+
return Number.isNaN(ms) ? defaultValue : ms;
|
|
16121
|
+
}
|
|
16122
|
+
function dumpTxWeight(tx, conversionResultSecurityIds) {
|
|
16123
|
+
const objectType = String(tx.object_type ?? "");
|
|
16124
|
+
if (conversionResultSecurityIds.size > 0 && ISSUANCE_TYPES.has(objectType) && typeof tx.security_id === "string" && conversionResultSecurityIds.has(tx.security_id)) {
|
|
16125
|
+
return 36;
|
|
16126
|
+
}
|
|
16127
|
+
switch (objectType) {
|
|
16128
|
+
case "TX_ISSUER_AUTHORIZED_SHARES_ADJUSTMENT":
|
|
16129
|
+
case "TX_STOCK_CLASS_AUTHORIZED_SHARES_ADJUSTMENT":
|
|
16130
|
+
case "TX_STOCK_PLAN_POOL_ADJUSTMENT":
|
|
16131
|
+
return 5;
|
|
16132
|
+
case "TX_STOCK_REISSUANCE":
|
|
16133
|
+
return 9;
|
|
16134
|
+
case "TX_STOCK_ISSUANCE":
|
|
16135
|
+
case "TX_EQUITY_COMPENSATION_ISSUANCE":
|
|
16136
|
+
case "TX_WARRANT_ISSUANCE":
|
|
16137
|
+
case "TX_CONVERTIBLE_ISSUANCE":
|
|
16138
|
+
case "TX_PLAN_SECURITY_ISSUANCE":
|
|
16139
|
+
return 10;
|
|
16140
|
+
case "TX_STOCK_ACCEPTANCE":
|
|
16141
|
+
case "TX_WARRANT_ACCEPTANCE":
|
|
16142
|
+
case "TX_EQUITY_COMPENSATION_ACCEPTANCE":
|
|
16143
|
+
case "TX_PLAN_SECURITY_ACCEPTANCE":
|
|
16144
|
+
return 11;
|
|
16145
|
+
case "TX_VESTING_START":
|
|
16146
|
+
return 12;
|
|
16147
|
+
case "TX_VESTING_EVENT":
|
|
16148
|
+
return 13;
|
|
16149
|
+
case "TX_VESTING_ACCELERATION":
|
|
16150
|
+
return 14;
|
|
16151
|
+
case "TX_STOCK_CLASS_SPLIT":
|
|
16152
|
+
return 15;
|
|
16153
|
+
case "TX_STOCK_RETRACTION":
|
|
16154
|
+
case "TX_CONVERTIBLE_RETRACTION":
|
|
16155
|
+
case "TX_WARRANT_RETRACTION":
|
|
16156
|
+
case "TX_EQUITY_COMPENSATION_RETRACTION":
|
|
16157
|
+
return 16;
|
|
16158
|
+
case "TX_STOCK_CONSOLIDATION":
|
|
16159
|
+
return 17;
|
|
16160
|
+
case "TX_STOCK_CLASS_CONVERSION_RATIO_ADJUSTMENT":
|
|
16161
|
+
return 18;
|
|
16162
|
+
case "TX_EQUITY_COMPENSATION_REPRICING":
|
|
16163
|
+
return 19;
|
|
16164
|
+
case "TX_STOCK_TRANSFER":
|
|
16165
|
+
case "TX_WARRANT_TRANSFER":
|
|
16166
|
+
case "TX_CONVERTIBLE_TRANSFER":
|
|
16167
|
+
case "TX_EQUITY_COMPENSATION_TRANSFER":
|
|
16168
|
+
case "TX_PLAN_SECURITY_TRANSFER":
|
|
16169
|
+
return 20;
|
|
16170
|
+
case "TX_CONVERTIBLE_ACCEPTANCE":
|
|
16171
|
+
return 22;
|
|
16172
|
+
case "TX_EQUITY_COMPENSATION_EXERCISE":
|
|
16173
|
+
case "TX_WARRANT_EXERCISE":
|
|
16174
|
+
return 30;
|
|
16175
|
+
case "TX_CONVERTIBLE_CONVERSION":
|
|
16176
|
+
return 35;
|
|
16177
|
+
case "TX_STOCK_REPURCHASE":
|
|
16178
|
+
case "TX_STOCK_CANCELLATION":
|
|
16179
|
+
case "TX_EQUITY_COMPENSATION_CANCELLATION":
|
|
16180
|
+
case "TX_WARRANT_CANCELLATION":
|
|
16181
|
+
case "TX_CONVERTIBLE_CANCELLATION":
|
|
16182
|
+
case "TX_EQUITY_COMPENSATION_RETURN_TO_POOL":
|
|
16183
|
+
return 40;
|
|
16184
|
+
default:
|
|
16185
|
+
return 50;
|
|
16186
|
+
}
|
|
16187
|
+
}
|
|
16188
|
+
function dumpTransactionSortKey(tx, issuanceDates, conversionResultSecurityIds) {
|
|
16189
|
+
let day = new Date(timestampMs(tx.date, 0) ?? 0).toISOString().slice(0, 10);
|
|
16190
|
+
const objectType = String(tx.object_type ?? "");
|
|
16191
|
+
if (objectType === "TX_VESTING_START" && typeof tx.security_id === "string") {
|
|
16192
|
+
const issuanceDate = issuanceDates.get(tx.security_id);
|
|
16193
|
+
if (issuanceDate && String(tx.date) < issuanceDate) {
|
|
16194
|
+
day = new Date(timestampMs(issuanceDate, 0) ?? 0).toISOString().slice(0, 10);
|
|
16195
|
+
}
|
|
16196
|
+
}
|
|
16197
|
+
const weight = String(dumpTxWeight(tx, conversionResultSecurityIds)).padStart(3, "0");
|
|
16198
|
+
const group = typeof tx.security_id === "string" && tx.security_id ? tx.security_id : "_no_security_";
|
|
16199
|
+
const createdMs = timestampMs(tx.createdAt ?? tx.created_at, null);
|
|
16200
|
+
const created = createdMs !== null ? new Date(createdMs).toISOString() : "9999-12-31T23:59:59.999Z";
|
|
16201
|
+
const id = String(tx._id ?? tx.id ?? "");
|
|
16202
|
+
return `${day}|${weight}|${group}|${created}|${id}`;
|
|
16203
|
+
}
|
|
16204
|
+
function sortDumpTransactions(transactions) {
|
|
16205
|
+
const issuanceDates = /* @__PURE__ */ new Map();
|
|
16206
|
+
const conversionResultSecurityIds = /* @__PURE__ */ new Set();
|
|
16207
|
+
for (const tx of transactions) {
|
|
16208
|
+
const objectType = String(tx.object_type ?? "");
|
|
16209
|
+
if (ISSUANCE_TYPES.has(objectType) && typeof tx.security_id === "string" && typeof tx.date === "string") {
|
|
16210
|
+
issuanceDates.set(tx.security_id, tx.date);
|
|
16211
|
+
}
|
|
16212
|
+
if (!CONVERSION_PARENT_TYPES.has(objectType))
|
|
16213
|
+
continue;
|
|
16214
|
+
if (Array.isArray(tx.resulting_security_ids)) {
|
|
16215
|
+
for (const id of tx.resulting_security_ids) {
|
|
16216
|
+
if (typeof id === "string" && id)
|
|
16217
|
+
conversionResultSecurityIds.add(id);
|
|
16218
|
+
}
|
|
16219
|
+
}
|
|
16220
|
+
if (typeof tx.balance_security_id === "string" && tx.balance_security_id) {
|
|
16221
|
+
conversionResultSecurityIds.add(tx.balance_security_id);
|
|
16222
|
+
}
|
|
16223
|
+
}
|
|
16224
|
+
return [...transactions].sort((a, b) => {
|
|
16225
|
+
const ka = dumpTransactionSortKey(a, issuanceDates, conversionResultSecurityIds);
|
|
16226
|
+
const kb = dumpTransactionSortKey(b, issuanceDates, conversionResultSecurityIds);
|
|
16227
|
+
if (ka < kb)
|
|
16228
|
+
return -1;
|
|
16229
|
+
if (ka > kb)
|
|
16230
|
+
return 1;
|
|
16231
|
+
return 0;
|
|
16232
|
+
});
|
|
16233
|
+
}
|
|
16234
|
+
function assembleEngineOcfDump(objects) {
|
|
16235
|
+
const issuers = [];
|
|
16236
|
+
const stockClasses = /* @__PURE__ */ new Map();
|
|
16237
|
+
const stockPlans = /* @__PURE__ */ new Map();
|
|
16238
|
+
const stakeholders = /* @__PURE__ */ new Map();
|
|
16239
|
+
const transactions = /* @__PURE__ */ new Map();
|
|
16240
|
+
const vestingTerms = /* @__PURE__ */ new Map();
|
|
16241
|
+
let index = 0;
|
|
16242
|
+
for (const obj of objects) {
|
|
16243
|
+
if (!isRecord(obj))
|
|
16244
|
+
continue;
|
|
16245
|
+
const type = canonicalType(obj);
|
|
16246
|
+
const payload = isRecord(obj.ocf) ? obj.ocf : null;
|
|
16247
|
+
index += 1;
|
|
16248
|
+
switch (type) {
|
|
16249
|
+
case "ISSUER":
|
|
16250
|
+
if (!payload) {
|
|
16251
|
+
throw new DumpAssemblyError("ISSUER object is missing an ocf payload.");
|
|
16252
|
+
}
|
|
16253
|
+
issuers.push(issuerForEngine(payload));
|
|
16254
|
+
break;
|
|
16255
|
+
case "STOCK_CLASS":
|
|
16256
|
+
if (payload)
|
|
16257
|
+
pushByOcfId(stockClasses, payload, `anon-stock-class-${index}`);
|
|
16258
|
+
break;
|
|
16259
|
+
case "STOCK_PLAN":
|
|
16260
|
+
if (payload)
|
|
16261
|
+
pushByOcfId(stockPlans, payload, `anon-stock-plan-${index}`);
|
|
16262
|
+
break;
|
|
16263
|
+
case "STAKEHOLDER":
|
|
16264
|
+
if (payload)
|
|
16265
|
+
pushByOcfId(stakeholders, payload, `anon-stakeholder-${index}`);
|
|
16266
|
+
break;
|
|
16267
|
+
case "TRANSACTION":
|
|
16268
|
+
if (payload)
|
|
16269
|
+
pushByOcfId(transactions, payload, `anon-transaction-${index}`);
|
|
16270
|
+
break;
|
|
16271
|
+
case "VESTING_TERMS":
|
|
16272
|
+
if (payload)
|
|
16273
|
+
pushByOcfId(vestingTerms, payload, `anon-vesting-terms-${index}`);
|
|
16274
|
+
break;
|
|
16275
|
+
default:
|
|
16276
|
+
break;
|
|
16277
|
+
}
|
|
16278
|
+
}
|
|
16279
|
+
if (issuers.length === 0) {
|
|
16280
|
+
throw new DumpAssemblyError("Dump requires exactly one ISSUER object; none found.");
|
|
16281
|
+
}
|
|
16282
|
+
if (issuers.length > 1) {
|
|
16283
|
+
throw new DumpAssemblyError(`Dump requires exactly one ISSUER object; found ${issuers.length}.`);
|
|
16284
|
+
}
|
|
16285
|
+
return {
|
|
16286
|
+
issuer: issuers[0],
|
|
16287
|
+
stockClasses: [...stockClasses.values()],
|
|
16288
|
+
stockPlans: [...stockPlans.values()],
|
|
16289
|
+
stakeholders: [...stakeholders.values()],
|
|
16290
|
+
transactions: sortDumpTransactions([...transactions.values()]),
|
|
16291
|
+
vestingTerms: [...vestingTerms.values()],
|
|
16292
|
+
sharePrices: []
|
|
16293
|
+
};
|
|
16294
|
+
}
|
|
16295
|
+
|
|
16046
16296
|
// ../captable-ai-core/dist/scopes.js
|
|
16047
16297
|
var CAPTABLE_AI_SCOPES = {
|
|
16048
16298
|
READ: "read",
|
|
@@ -16203,14 +16453,14 @@ var summarySchema = external_exports.object({
|
|
|
16203
16453
|
});
|
|
16204
16454
|
|
|
16205
16455
|
// src/api.ts
|
|
16206
|
-
function
|
|
16456
|
+
function isRecord2(value) {
|
|
16207
16457
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16208
16458
|
}
|
|
16209
16459
|
function coerceDetails(raw) {
|
|
16210
16460
|
if (!Array.isArray(raw)) return void 0;
|
|
16211
16461
|
const details = [];
|
|
16212
16462
|
for (const entry of raw) {
|
|
16213
|
-
if (!
|
|
16463
|
+
if (!isRecord2(entry)) continue;
|
|
16214
16464
|
const message = typeof entry.message === "string" ? entry.message : void 0;
|
|
16215
16465
|
if (!message) continue;
|
|
16216
16466
|
const path = typeof entry.path === "string" ? entry.path : void 0;
|
|
@@ -16401,9 +16651,9 @@ async function handleResponse(res) {
|
|
|
16401
16651
|
}
|
|
16402
16652
|
if (!res.ok) {
|
|
16403
16653
|
const exitCode = exitCodeForStatus(res.status);
|
|
16404
|
-
const obj =
|
|
16654
|
+
const obj = isRecord2(parsed) ? parsed : {};
|
|
16405
16655
|
const nested = obj.error;
|
|
16406
|
-
if (
|
|
16656
|
+
if (isRecord2(nested)) {
|
|
16407
16657
|
const code = typeof nested.code === "string" && nested.code.trim() ? nested.code : void 0;
|
|
16408
16658
|
const details = coerceDetails(nested.details);
|
|
16409
16659
|
exitWithError(String(nested.message ?? `HTTP ${res.status}`), code, details, exitCode);
|
|
@@ -16531,6 +16781,29 @@ var HELP_OBJECTS_GET = `objects get \u2014 Show one OCF object
|
|
|
16531
16781
|
|
|
16532
16782
|
Usage:
|
|
16533
16783
|
captable-ai objects get <object-id> [--json]`;
|
|
16784
|
+
var HELP_OBJECTS_DUMP = `objects dump \u2014 Engine-shaped ocf.json
|
|
16785
|
+
|
|
16786
|
+
Assembles each row's ocf payload into the shape processCapTable consumes:
|
|
16787
|
+
{ issuer, stockClasses, stockPlans, stakeholders, transactions, vestingTerms, sharePrices }
|
|
16788
|
+
|
|
16789
|
+
Fails if ISSUER is missing or duplicated. Not an OCF zip and not expected.json.
|
|
16790
|
+
Drains up to 400 pages (100,000 objects). Large tables: write a file with --output.
|
|
16791
|
+
|
|
16792
|
+
The list API picks the latest row per object id, then optionally filters status.
|
|
16793
|
+
--status committed therefore omits an object when a newer draft exists.
|
|
16794
|
+
--status draft dumps that latest-row working set (drafts win) so the engine
|
|
16795
|
+
still sees the committed ISSUER and other unchanged baseline objects.
|
|
16796
|
+
|
|
16797
|
+
Usage:
|
|
16798
|
+
captable-ai objects dump [--status committed|draft] [--output path]
|
|
16799
|
+
|
|
16800
|
+
Flags:
|
|
16801
|
+
--status STATUS committed = latest committed-only rows (default).
|
|
16802
|
+
draft = pending working set (latest row per object).
|
|
16803
|
+
--output PATH Write JSON to file (global flag; implies --json)
|
|
16804
|
+
|
|
16805
|
+
Global:
|
|
16806
|
+
--json Machine-readable JSON (dump is always JSON)`;
|
|
16534
16807
|
var HELP_OBJECTS_UPDATE = `objects update \u2014 Update an OCF object
|
|
16535
16808
|
|
|
16536
16809
|
Usage:
|
|
@@ -16619,6 +16892,8 @@ ${HELP_OBJECTS_LIST}
|
|
|
16619
16892
|
|
|
16620
16893
|
${HELP_OBJECTS_GET}
|
|
16621
16894
|
|
|
16895
|
+
${HELP_OBJECTS_DUMP}
|
|
16896
|
+
|
|
16622
16897
|
${HELP_OBJECTS_UPDATE}
|
|
16623
16898
|
|
|
16624
16899
|
${HELP_OBJECTS_PATCH}
|
|
@@ -17713,11 +17988,11 @@ var JOBS_FILE = join2(CONFIG_DIR2, "jobs.jsonl");
|
|
|
17713
17988
|
var LOCK_DIR = join2(CONFIG_DIR2, "jobs.lock");
|
|
17714
17989
|
var VALID_JOB_STATUSES = /* @__PURE__ */ new Set(["submitted", "running", "complete", "failed"]);
|
|
17715
17990
|
var VALID_JOB_KINDS = /* @__PURE__ */ new Set(["extraction"]);
|
|
17716
|
-
function
|
|
17991
|
+
function isRecord3(v) {
|
|
17717
17992
|
return typeof v === "object" && v !== null;
|
|
17718
17993
|
}
|
|
17719
17994
|
function isJobEntry(value) {
|
|
17720
|
-
if (!
|
|
17995
|
+
if (!isRecord3(value)) return false;
|
|
17721
17996
|
return typeof value.id === "string" && typeof value.kind === "string" && VALID_JOB_KINDS.has(value.kind) && typeof value.portalId === "string" && typeof value.submittedAt === "string" && typeof value.status === "string" && VALID_JOB_STATUSES.has(value.status);
|
|
17722
17997
|
}
|
|
17723
17998
|
async function ensureDir() {
|
|
@@ -18268,11 +18543,11 @@ async function readEntries() {
|
|
|
18268
18543
|
}
|
|
18269
18544
|
return entries;
|
|
18270
18545
|
}
|
|
18271
|
-
function
|
|
18546
|
+
function isRecord4(v) {
|
|
18272
18547
|
return typeof v === "object" && v !== null;
|
|
18273
18548
|
}
|
|
18274
18549
|
function isFeedbackEntry(value) {
|
|
18275
|
-
if (!
|
|
18550
|
+
if (!isRecord4(value)) return false;
|
|
18276
18551
|
return typeof value.ts === "string" && typeof value.text === "string" && typeof value.sent === "boolean";
|
|
18277
18552
|
}
|
|
18278
18553
|
|
|
@@ -18489,7 +18764,7 @@ function successHtml() {
|
|
|
18489
18764
|
h1{font-size:1.5rem;color:#111}p{color:#666}</style></head>
|
|
18490
18765
|
<body><div class="card"><h1>Login successful</h1><p>You can close this window and return to the terminal.</p></div></body></html>`;
|
|
18491
18766
|
}
|
|
18492
|
-
function
|
|
18767
|
+
function isRecord5(value) {
|
|
18493
18768
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
18494
18769
|
}
|
|
18495
18770
|
function readStr(obj, ...keys) {
|
|
@@ -18510,7 +18785,7 @@ function parsePortalsFromExchange(raw) {
|
|
|
18510
18785
|
}
|
|
18511
18786
|
if (!Array.isArray(parsed)) return [];
|
|
18512
18787
|
return parsed.flatMap((p) => {
|
|
18513
|
-
if (!
|
|
18788
|
+
if (!isRecord5(p)) return [];
|
|
18514
18789
|
if (typeof p.id !== "string" || p.id.length === 0) return [];
|
|
18515
18790
|
return [
|
|
18516
18791
|
{
|
|
@@ -18554,7 +18829,7 @@ function tryParseLoginPaste(line, expectedState) {
|
|
|
18554
18829
|
} catch {
|
|
18555
18830
|
return null;
|
|
18556
18831
|
}
|
|
18557
|
-
if (!
|
|
18832
|
+
if (!isRecord5(obj)) return null;
|
|
18558
18833
|
if (typeof obj.state !== "string" || !pastedStateMatches(expectedState, obj.state)) return null;
|
|
18559
18834
|
const accessToken = readStr(obj, "access_token", "accessToken");
|
|
18560
18835
|
const refreshToken = readStr(obj, "refresh_token", "refreshToken");
|
|
@@ -18919,6 +19194,105 @@ async function runObjectsDelete(args, rawArgv) {
|
|
|
18919
19194
|
);
|
|
18920
19195
|
}
|
|
18921
19196
|
|
|
19197
|
+
// src/objects-pages.ts
|
|
19198
|
+
var OBJECTS_LIST_MAX_PAGES = 100;
|
|
19199
|
+
var OBJECTS_DUMP_MAX_PAGES = 400;
|
|
19200
|
+
async function fetchAllObjectPages(portalId, query, options) {
|
|
19201
|
+
const maxPages = options?.maxPages ?? OBJECTS_LIST_MAX_PAGES;
|
|
19202
|
+
const objects = [];
|
|
19203
|
+
const documentsById = /* @__PURE__ */ new Map();
|
|
19204
|
+
let cursor = typeof query.cursor === "string" ? query.cursor : void 0;
|
|
19205
|
+
let total = 0;
|
|
19206
|
+
let pages = 0;
|
|
19207
|
+
while (true) {
|
|
19208
|
+
pages += 1;
|
|
19209
|
+
if (pages > maxPages) {
|
|
19210
|
+
exitWithError(
|
|
19211
|
+
`Exceeded max object-list pages (${maxPages}). Narrow the query or raise the page size.`,
|
|
19212
|
+
"ERROR",
|
|
19213
|
+
void 0,
|
|
19214
|
+
EXIT.SERVER_ERROR
|
|
19215
|
+
);
|
|
19216
|
+
}
|
|
19217
|
+
const pageQuery = { ...query };
|
|
19218
|
+
if (cursor !== void 0) pageQuery.cursor = cursor;
|
|
19219
|
+
else delete pageQuery.cursor;
|
|
19220
|
+
const res = await apiRequest(`/${portalId}/objects`, { query: pageQuery });
|
|
19221
|
+
const pageObjects = res.data?.objects ?? [];
|
|
19222
|
+
const pageDocs = res.data?.documents ?? [];
|
|
19223
|
+
objects.push(...pageObjects);
|
|
19224
|
+
for (const doc of pageDocs) {
|
|
19225
|
+
documentsById.set(doc.id, doc);
|
|
19226
|
+
}
|
|
19227
|
+
if (res.meta?.total != null) total = res.meta.total;
|
|
19228
|
+
if (!res.meta?.hasMore) break;
|
|
19229
|
+
if (!res.meta.cursor) {
|
|
19230
|
+
exitWithError(
|
|
19231
|
+
"Pagination response has more results but no continuation cursor.",
|
|
19232
|
+
"ERROR",
|
|
19233
|
+
void 0,
|
|
19234
|
+
EXIT.SERVER_ERROR
|
|
19235
|
+
);
|
|
19236
|
+
}
|
|
19237
|
+
if (cursor !== void 0 && res.meta.cursor === cursor) {
|
|
19238
|
+
exitWithError(
|
|
19239
|
+
"Pagination cursor did not advance; stopped draining object pages.",
|
|
19240
|
+
"ERROR",
|
|
19241
|
+
void 0,
|
|
19242
|
+
EXIT.SERVER_ERROR
|
|
19243
|
+
);
|
|
19244
|
+
}
|
|
19245
|
+
cursor = res.meta.cursor;
|
|
19246
|
+
}
|
|
19247
|
+
return {
|
|
19248
|
+
data: { objects, documents: Array.from(documentsById.values()) },
|
|
19249
|
+
meta: { cursor: null, total: total || objects.length, hasMore: false }
|
|
19250
|
+
};
|
|
19251
|
+
}
|
|
19252
|
+
|
|
19253
|
+
// src/commands/objects-dump.ts
|
|
19254
|
+
var DUMP_PAGE_LIMIT = 250;
|
|
19255
|
+
function dumpStatus(raw) {
|
|
19256
|
+
const status = raw ?? "committed";
|
|
19257
|
+
if (status === "committed" || status === "draft") return status;
|
|
19258
|
+
exitWithError(
|
|
19259
|
+
`--status must be one of: draft, committed (got: "${status}")`,
|
|
19260
|
+
"VALIDATION_FAILED",
|
|
19261
|
+
void 0,
|
|
19262
|
+
EXIT.VALIDATION
|
|
19263
|
+
);
|
|
19264
|
+
}
|
|
19265
|
+
async function runObjectsDump(args, rawArgv) {
|
|
19266
|
+
if (argvRequestsHelp(rawArgv)) {
|
|
19267
|
+
process.stdout.write(`${HELP_OBJECTS_DUMP}
|
|
19268
|
+
`);
|
|
19269
|
+
process.exit(0);
|
|
19270
|
+
}
|
|
19271
|
+
validateFlags(args, { flags: ["status"], booleans: [] });
|
|
19272
|
+
if (args.positional.length > 0) {
|
|
19273
|
+
exitWithError(
|
|
19274
|
+
`Unexpected argument: ${args.positional[0]}. objects dump takes flags only.`,
|
|
19275
|
+
"USAGE",
|
|
19276
|
+
void 0,
|
|
19277
|
+
EXIT.USAGE
|
|
19278
|
+
);
|
|
19279
|
+
}
|
|
19280
|
+
const status = dumpStatus(getFlagValue(args, "status"));
|
|
19281
|
+
const portalId = await getActivePortalId();
|
|
19282
|
+
const query = { limit: DUMP_PAGE_LIMIT };
|
|
19283
|
+
if (status === "committed") query.status = "committed";
|
|
19284
|
+
const page = await fetchAllObjectPages(portalId, query, { maxPages: OBJECTS_DUMP_MAX_PAGES });
|
|
19285
|
+
try {
|
|
19286
|
+
const objects = Array.isArray(page.data?.objects) ? page.data.objects : [];
|
|
19287
|
+
printJson(assembleEngineOcfDump(objects));
|
|
19288
|
+
} catch (err) {
|
|
19289
|
+
if (err instanceof DumpAssemblyError) {
|
|
19290
|
+
exitWithError(err.message, "VALIDATION_FAILED", void 0, EXIT.VALIDATION);
|
|
19291
|
+
}
|
|
19292
|
+
throw err;
|
|
19293
|
+
}
|
|
19294
|
+
}
|
|
19295
|
+
|
|
18922
19296
|
// src/commands/objects-get.ts
|
|
18923
19297
|
function shellQuote2(value) {
|
|
18924
19298
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
@@ -18980,60 +19354,6 @@ Object: ${obj.id}
|
|
|
18980
19354
|
printLine();
|
|
18981
19355
|
}
|
|
18982
19356
|
|
|
18983
|
-
// src/objects-pages.ts
|
|
18984
|
-
var OBJECTS_LIST_MAX_PAGES = 100;
|
|
18985
|
-
async function fetchAllObjectPages(portalId, query) {
|
|
18986
|
-
const objects = [];
|
|
18987
|
-
const documentsById = /* @__PURE__ */ new Map();
|
|
18988
|
-
let cursor = typeof query.cursor === "string" ? query.cursor : void 0;
|
|
18989
|
-
let total = 0;
|
|
18990
|
-
let pages = 0;
|
|
18991
|
-
while (true) {
|
|
18992
|
-
pages += 1;
|
|
18993
|
-
if (pages > OBJECTS_LIST_MAX_PAGES) {
|
|
18994
|
-
exitWithError(
|
|
18995
|
-
`Exceeded max object-list pages (${OBJECTS_LIST_MAX_PAGES}). Narrow the query or raise the page size.`,
|
|
18996
|
-
"ERROR",
|
|
18997
|
-
void 0,
|
|
18998
|
-
EXIT.SERVER_ERROR
|
|
18999
|
-
);
|
|
19000
|
-
}
|
|
19001
|
-
const pageQuery = { ...query };
|
|
19002
|
-
if (cursor !== void 0) pageQuery.cursor = cursor;
|
|
19003
|
-
else delete pageQuery.cursor;
|
|
19004
|
-
const res = await apiRequest(`/${portalId}/objects`, { query: pageQuery });
|
|
19005
|
-
const pageObjects = res.data?.objects ?? [];
|
|
19006
|
-
const pageDocs = res.data?.documents ?? [];
|
|
19007
|
-
objects.push(...pageObjects);
|
|
19008
|
-
for (const doc of pageDocs) {
|
|
19009
|
-
documentsById.set(doc.id, doc);
|
|
19010
|
-
}
|
|
19011
|
-
if (res.meta?.total != null) total = res.meta.total;
|
|
19012
|
-
if (!res.meta?.hasMore) break;
|
|
19013
|
-
if (!res.meta.cursor) {
|
|
19014
|
-
exitWithError(
|
|
19015
|
-
"Pagination response has more results but no continuation cursor.",
|
|
19016
|
-
"ERROR",
|
|
19017
|
-
void 0,
|
|
19018
|
-
EXIT.SERVER_ERROR
|
|
19019
|
-
);
|
|
19020
|
-
}
|
|
19021
|
-
if (cursor !== void 0 && res.meta.cursor === cursor) {
|
|
19022
|
-
exitWithError(
|
|
19023
|
-
"Pagination cursor did not advance; stopped draining object pages.",
|
|
19024
|
-
"ERROR",
|
|
19025
|
-
void 0,
|
|
19026
|
-
EXIT.SERVER_ERROR
|
|
19027
|
-
);
|
|
19028
|
-
}
|
|
19029
|
-
cursor = res.meta.cursor;
|
|
19030
|
-
}
|
|
19031
|
-
return {
|
|
19032
|
-
data: { objects, documents: Array.from(documentsById.values()) },
|
|
19033
|
-
meta: { cursor: null, total: total || objects.length, hasMore: false }
|
|
19034
|
-
};
|
|
19035
|
-
}
|
|
19036
|
-
|
|
19037
19357
|
// src/validate.ts
|
|
19038
19358
|
var ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
19039
19359
|
function isValidCalendarIsoDate(s) {
|
|
@@ -19103,7 +19423,7 @@ function validateIsoDateRange(fromRaw, toRaw) {
|
|
|
19103
19423
|
// src/commands/objects-list.ts
|
|
19104
19424
|
var CONFIDENCE_RED_MAX = 64;
|
|
19105
19425
|
var CONFIDENCE_AMBER_MAX = 84;
|
|
19106
|
-
function
|
|
19426
|
+
function isRecord6(value) {
|
|
19107
19427
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19108
19428
|
}
|
|
19109
19429
|
function getValidatedMaxConfidence(raw) {
|
|
@@ -19142,7 +19462,7 @@ function stakeholderDisplayName(ocf) {
|
|
|
19142
19462
|
if (!ocf) return null;
|
|
19143
19463
|
if (typeof ocf.name === "string" && ocf.name.trim()) return ocf.name.trim();
|
|
19144
19464
|
if (typeof ocf.legal_name === "string" && ocf.legal_name.trim()) return ocf.legal_name.trim();
|
|
19145
|
-
if (
|
|
19465
|
+
if (isRecord6(ocf.name)) {
|
|
19146
19466
|
const legal = ocf.name.legal_name;
|
|
19147
19467
|
if (typeof legal === "string" && legal.trim()) return legal.trim();
|
|
19148
19468
|
const parts = [ocf.name.first_name, ocf.name.last_name].filter(
|
|
@@ -19354,7 +19674,7 @@ async function readStdin() {
|
|
|
19354
19674
|
}
|
|
19355
19675
|
return Buffer.concat(chunks).toString("utf-8");
|
|
19356
19676
|
}
|
|
19357
|
-
function
|
|
19677
|
+
function isRecord7(value) {
|
|
19358
19678
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19359
19679
|
}
|
|
19360
19680
|
function parsePatchPayload(raw) {
|
|
@@ -19369,7 +19689,7 @@ function parsePatchPayload(raw) {
|
|
|
19369
19689
|
EXIT.VALIDATION
|
|
19370
19690
|
);
|
|
19371
19691
|
}
|
|
19372
|
-
if (!
|
|
19692
|
+
if (!isRecord7(parsed)) {
|
|
19373
19693
|
exitWithError(
|
|
19374
19694
|
"OCF patch payload must be a JSON object.",
|
|
19375
19695
|
"VALIDATION_FAILED",
|
|
@@ -19589,7 +19909,7 @@ async function readStdin2() {
|
|
|
19589
19909
|
}
|
|
19590
19910
|
return Buffer.concat(chunks).toString("utf-8");
|
|
19591
19911
|
}
|
|
19592
|
-
function
|
|
19912
|
+
function isRecord8(value) {
|
|
19593
19913
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19594
19914
|
}
|
|
19595
19915
|
function parseOcfPayload(raw) {
|
|
@@ -19604,7 +19924,7 @@ function parseOcfPayload(raw) {
|
|
|
19604
19924
|
EXIT.VALIDATION
|
|
19605
19925
|
);
|
|
19606
19926
|
}
|
|
19607
|
-
if (!
|
|
19927
|
+
if (!isRecord8(parsed)) {
|
|
19608
19928
|
exitWithError(
|
|
19609
19929
|
"OCF payload must be a JSON object.",
|
|
19610
19930
|
"VALIDATION_FAILED",
|
|
@@ -19973,20 +20293,20 @@ import { homedir as homedir4 } from "os";
|
|
|
19973
20293
|
import { join as join4 } from "path";
|
|
19974
20294
|
var CONFIG_DIR4 = join4(homedir4(), ".captable-ai");
|
|
19975
20295
|
var PROFILES_FILE = join4(CONFIG_DIR4, "profiles.json");
|
|
19976
|
-
function
|
|
20296
|
+
function isRecord9(value) {
|
|
19977
20297
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19978
20298
|
}
|
|
19979
20299
|
function isErrno3(err, code) {
|
|
19980
|
-
return
|
|
20300
|
+
return isRecord9(err) && err.code === code;
|
|
19981
20301
|
}
|
|
19982
20302
|
function parseProfiles(raw) {
|
|
19983
20303
|
const parsed = JSON.parse(raw);
|
|
19984
|
-
if (!
|
|
20304
|
+
if (!isRecord9(parsed) || !isRecord9(parsed.profiles)) {
|
|
19985
20305
|
throw new Error("profiles.json must contain a profiles object.");
|
|
19986
20306
|
}
|
|
19987
20307
|
const profiles = {};
|
|
19988
20308
|
for (const [name, value] of Object.entries(parsed.profiles)) {
|
|
19989
|
-
if (!
|
|
20309
|
+
if (!isRecord9(value) || typeof value.company !== "string" || !value.company.trim()) {
|
|
19990
20310
|
throw new Error(`Profile "${name}" must include a non-empty company string.`);
|
|
19991
20311
|
}
|
|
19992
20312
|
const stage = typeof value.stage === "string" && value.stage.trim() ? value.stage : void 0;
|
|
@@ -20671,6 +20991,7 @@ Cap Table (read):
|
|
|
20671
20991
|
Pagination: --limit (1-250), --cursor, --all
|
|
20672
20992
|
Dates: --from / --to as YYYY-MM-DD
|
|
20673
20993
|
objects get <id> Show a single OCF object
|
|
20994
|
+
objects dump Engine-shaped ocf.json (default --status committed; --output path)
|
|
20674
20995
|
schemas list List OCF object types
|
|
20675
20996
|
schemas get <type> Show schema for an OCF type
|
|
20676
20997
|
|
|
@@ -20957,6 +21278,9 @@ async function main() {
|
|
|
20957
21278
|
case "get":
|
|
20958
21279
|
await runObjectsGet(parseArgs(positionalArgs.slice(2)), positionalArgs.slice(2));
|
|
20959
21280
|
break;
|
|
21281
|
+
case "dump":
|
|
21282
|
+
await runObjectsDump(parseArgs(positionalArgs.slice(2)), positionalArgs.slice(2));
|
|
21283
|
+
break;
|
|
20960
21284
|
case "update":
|
|
20961
21285
|
await runObjectsUpdate(parseArgs(positionalArgs.slice(2)), positionalArgs.slice(2));
|
|
20962
21286
|
break;
|
|
@@ -20974,7 +21298,7 @@ async function main() {
|
|
|
20974
21298
|
break;
|
|
20975
21299
|
default:
|
|
20976
21300
|
exitWithError(
|
|
20977
|
-
`Unknown objects command: ${sub ?? "(none)"}. Try: objects list | get | update | patch | revert | versions | delete`,
|
|
21301
|
+
`Unknown objects command: ${sub ?? "(none)"}. Try: objects list | get | dump | update | patch | revert | versions | delete`,
|
|
20978
21302
|
"UNKNOWN_COMMAND",
|
|
20979
21303
|
void 0,
|
|
20980
21304
|
EXIT.USAGE
|
package/package.json
CHANGED