@thecorporation/corp-tools 26.3.24 → 26.3.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.d.ts +3464 -0
- package/dist/browser.js +1518 -0
- package/dist/browser.js.map +1 -0
- package/dist/index.d.ts +157 -1
- package/dist/index.js +694 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
package/dist/index.js
CHANGED
|
@@ -343,6 +343,18 @@ var CorpAPIClient = class {
|
|
|
343
343
|
const resp = await this.request("DELETE", path);
|
|
344
344
|
await this.throwIfError(resp);
|
|
345
345
|
}
|
|
346
|
+
/** Public generic GET for declarative/registry-driven commands. */
|
|
347
|
+
async fetchJSON(path, params) {
|
|
348
|
+
return this.get(path, params);
|
|
349
|
+
}
|
|
350
|
+
/** Public generic request for declarative/registry-driven write commands. */
|
|
351
|
+
async submitJSON(method, path, body) {
|
|
352
|
+
const resp = await this.request(method, path, body);
|
|
353
|
+
await this.throwIfError(resp);
|
|
354
|
+
const text = await resp.text();
|
|
355
|
+
if (!text) return {};
|
|
356
|
+
return JSON.parse(text);
|
|
357
|
+
}
|
|
346
358
|
// --- Workspace ---
|
|
347
359
|
getStatus() {
|
|
348
360
|
return this.get(`/v1/workspaces/${pathSegment(this.workspaceId)}/status`);
|
|
@@ -721,6 +733,13 @@ var CorpAPIClient = class {
|
|
|
721
733
|
getSignerToken(obligationId) {
|
|
722
734
|
return this.post(`/v1/human-obligations/${pathSegment(obligationId)}/signer-token`);
|
|
723
735
|
}
|
|
736
|
+
// --- Next Steps ---
|
|
737
|
+
getEntityNextSteps(entityId) {
|
|
738
|
+
return this.get(`/v1/entities/${pathSegment(entityId)}/next-steps`);
|
|
739
|
+
}
|
|
740
|
+
getWorkspaceNextSteps() {
|
|
741
|
+
return this.get(`/v1/workspaces/${pathSegment(this.workspaceId)}/next-steps`);
|
|
742
|
+
}
|
|
724
743
|
// --- Demo ---
|
|
725
744
|
seedDemo(data) {
|
|
726
745
|
return this.post("/v1/demo/seed", data);
|
|
@@ -2298,6 +2317,651 @@ var VotingMethod = ["per_capita", "per_unit"];
|
|
|
2298
2317
|
var WorkItemActorTypeValue = ["contact", "agent"];
|
|
2299
2318
|
var WorkItemStatus = ["open", "claimed", "completed", "cancelled"];
|
|
2300
2319
|
var WorkflowType = ["transfer", "fundraising"];
|
|
2320
|
+
|
|
2321
|
+
// src/reference-tracker.ts
|
|
2322
|
+
var RESOURCE_KINDS = [
|
|
2323
|
+
"entity",
|
|
2324
|
+
"contact",
|
|
2325
|
+
"share_transfer",
|
|
2326
|
+
"invoice",
|
|
2327
|
+
"bank_account",
|
|
2328
|
+
"payment",
|
|
2329
|
+
"payroll_run",
|
|
2330
|
+
"distribution",
|
|
2331
|
+
"reconciliation",
|
|
2332
|
+
"tax_filing",
|
|
2333
|
+
"deadline",
|
|
2334
|
+
"classification",
|
|
2335
|
+
"body",
|
|
2336
|
+
"meeting",
|
|
2337
|
+
"seat",
|
|
2338
|
+
"agenda_item",
|
|
2339
|
+
"resolution",
|
|
2340
|
+
"document",
|
|
2341
|
+
"work_item",
|
|
2342
|
+
"agent",
|
|
2343
|
+
"valuation",
|
|
2344
|
+
"safe_note",
|
|
2345
|
+
"instrument",
|
|
2346
|
+
"share_class",
|
|
2347
|
+
"round",
|
|
2348
|
+
"service_request"
|
|
2349
|
+
];
|
|
2350
|
+
var VALID_RESOURCE_KINDS = new Set(RESOURCE_KINDS);
|
|
2351
|
+
var MAX_REFERENCE_INPUT_LEN = 256;
|
|
2352
|
+
function normalize(value) {
|
|
2353
|
+
return value.trim().toLowerCase();
|
|
2354
|
+
}
|
|
2355
|
+
function validateReferenceInput(value, field, options = {}) {
|
|
2356
|
+
const trimmed = value.trim();
|
|
2357
|
+
if (!options.allowEmpty && trimmed.length === 0) {
|
|
2358
|
+
throw new Error(`${field} cannot be empty.`);
|
|
2359
|
+
}
|
|
2360
|
+
if (trimmed.length > MAX_REFERENCE_INPUT_LEN) {
|
|
2361
|
+
throw new Error(`${field} must be at most ${MAX_REFERENCE_INPUT_LEN} characters.`);
|
|
2362
|
+
}
|
|
2363
|
+
return trimmed;
|
|
2364
|
+
}
|
|
2365
|
+
function shortId(value) {
|
|
2366
|
+
return String(value ?? "").slice(0, 8);
|
|
2367
|
+
}
|
|
2368
|
+
function slugify(value) {
|
|
2369
|
+
return String(value ?? "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
2370
|
+
}
|
|
2371
|
+
function isOpaqueUuid(value) {
|
|
2372
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(
|
|
2373
|
+
value.trim()
|
|
2374
|
+
);
|
|
2375
|
+
}
|
|
2376
|
+
function isShortIdCandidate(value) {
|
|
2377
|
+
const trimmed = value.trim();
|
|
2378
|
+
return /^[0-9a-f-]{4,}$/i.test(trimmed) || /^[a-z]+_[a-z0-9_-]{3,}$/i.test(trimmed);
|
|
2379
|
+
}
|
|
2380
|
+
function parseLastReference(value) {
|
|
2381
|
+
const trimmed = validateReferenceInput(value, "reference", { allowEmpty: false }).toLowerCase();
|
|
2382
|
+
if (trimmed === "_" || trimmed === "@last") {
|
|
2383
|
+
return { isLast: true };
|
|
2384
|
+
}
|
|
2385
|
+
if (trimmed.startsWith("@last:")) {
|
|
2386
|
+
const kind = trimmed.slice(6);
|
|
2387
|
+
if (!VALID_RESOURCE_KINDS.has(kind)) {
|
|
2388
|
+
throw new Error(`Unknown reference kind: ${kind}`);
|
|
2389
|
+
}
|
|
2390
|
+
return { isLast: true, kind };
|
|
2391
|
+
}
|
|
2392
|
+
return { isLast: false };
|
|
2393
|
+
}
|
|
2394
|
+
function uniqueStrings(values) {
|
|
2395
|
+
const out = /* @__PURE__ */ new Set();
|
|
2396
|
+
for (const value of values) {
|
|
2397
|
+
if (!value) continue;
|
|
2398
|
+
const trimmed = value.trim();
|
|
2399
|
+
if (!trimmed) continue;
|
|
2400
|
+
out.add(normalize(trimmed));
|
|
2401
|
+
const slug = slugify(trimmed);
|
|
2402
|
+
if (slug) out.add(slug);
|
|
2403
|
+
}
|
|
2404
|
+
return out;
|
|
2405
|
+
}
|
|
2406
|
+
function kindLabel(kind) {
|
|
2407
|
+
return kind.replaceAll("_", " ");
|
|
2408
|
+
}
|
|
2409
|
+
function isEntityScopedKind(kind) {
|
|
2410
|
+
return kind !== "entity" && kind !== "agent";
|
|
2411
|
+
}
|
|
2412
|
+
function extractId(record, fields) {
|
|
2413
|
+
for (const field of fields) {
|
|
2414
|
+
const value = record[field];
|
|
2415
|
+
if (typeof value === "string" && value.trim()) {
|
|
2416
|
+
return value.trim();
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
return void 0;
|
|
2420
|
+
}
|
|
2421
|
+
function isValidResourceKind(kind) {
|
|
2422
|
+
return VALID_RESOURCE_KINDS.has(kind);
|
|
2423
|
+
}
|
|
2424
|
+
function describeReferenceRecord(kind, record) {
|
|
2425
|
+
const specs = {
|
|
2426
|
+
entity: { idFields: ["entity_id", "id"], labelFields: ["legal_name", "name"] },
|
|
2427
|
+
contact: { idFields: ["contact_id", "id"], labelFields: ["name", "email"] },
|
|
2428
|
+
share_transfer: {
|
|
2429
|
+
idFields: ["transfer_id", "id"],
|
|
2430
|
+
labelFields: ["from_holder", "to_holder", "transfer_type", "status"]
|
|
2431
|
+
},
|
|
2432
|
+
invoice: {
|
|
2433
|
+
idFields: ["invoice_id", "id"],
|
|
2434
|
+
labelFields: ["customer_name", "description", "due_date"]
|
|
2435
|
+
},
|
|
2436
|
+
bank_account: {
|
|
2437
|
+
idFields: ["bank_account_id", "account_id", "id"],
|
|
2438
|
+
labelFields: ["bank_name", "account_type"]
|
|
2439
|
+
},
|
|
2440
|
+
payment: {
|
|
2441
|
+
idFields: ["payment_id", "id"],
|
|
2442
|
+
labelFields: ["recipient", "description", "payment_method"]
|
|
2443
|
+
},
|
|
2444
|
+
payroll_run: {
|
|
2445
|
+
idFields: ["payroll_run_id", "id"],
|
|
2446
|
+
labelFields: ["pay_period_start", "pay_period_end"]
|
|
2447
|
+
},
|
|
2448
|
+
distribution: {
|
|
2449
|
+
idFields: ["distribution_id", "id"],
|
|
2450
|
+
labelFields: ["description", "distribution_type"]
|
|
2451
|
+
},
|
|
2452
|
+
reconciliation: {
|
|
2453
|
+
idFields: ["reconciliation_id", "id"],
|
|
2454
|
+
labelFields: ["as_of_date", "status"]
|
|
2455
|
+
},
|
|
2456
|
+
tax_filing: {
|
|
2457
|
+
idFields: ["filing_id", "id"],
|
|
2458
|
+
labelFields: ["document_type", "tax_year"]
|
|
2459
|
+
},
|
|
2460
|
+
deadline: {
|
|
2461
|
+
idFields: ["deadline_id", "id"],
|
|
2462
|
+
labelFields: ["deadline_type", "description", "due_date"]
|
|
2463
|
+
},
|
|
2464
|
+
classification: {
|
|
2465
|
+
idFields: ["classification_id", "id"],
|
|
2466
|
+
labelFields: ["contractor_name", "state", "risk_level"]
|
|
2467
|
+
},
|
|
2468
|
+
body: { idFields: ["body_id", "id"], labelFields: ["name"] },
|
|
2469
|
+
meeting: { idFields: ["meeting_id", "id"], labelFields: ["title", "name"] },
|
|
2470
|
+
seat: {
|
|
2471
|
+
idFields: ["seat_id", "id"],
|
|
2472
|
+
labelFields: ["seat_name", "title", "holder_name", "holder", "holder_email"]
|
|
2473
|
+
},
|
|
2474
|
+
agenda_item: { idFields: ["agenda_item_id", "item_id", "id"], labelFields: ["title"] },
|
|
2475
|
+
resolution: { idFields: ["resolution_id", "id"], labelFields: ["title"] },
|
|
2476
|
+
document: { idFields: ["document_id", "id"], labelFields: ["title", "name"] },
|
|
2477
|
+
work_item: { idFields: ["work_item_id", "id"], labelFields: ["title"] },
|
|
2478
|
+
agent: { idFields: ["agent_id", "id"], labelFields: ["name"] },
|
|
2479
|
+
valuation: {
|
|
2480
|
+
idFields: ["valuation_id", "id"],
|
|
2481
|
+
labelFields: ["valuation_type", "effective_date", "date"]
|
|
2482
|
+
},
|
|
2483
|
+
safe_note: {
|
|
2484
|
+
idFields: ["safe_note_id", "safe_id", "id"],
|
|
2485
|
+
labelFields: ["investor_name", "investor", "safe_type"]
|
|
2486
|
+
},
|
|
2487
|
+
instrument: { idFields: ["instrument_id", "id"], labelFields: ["symbol", "kind", "name"] },
|
|
2488
|
+
share_class: {
|
|
2489
|
+
idFields: ["share_class_id", "id"],
|
|
2490
|
+
labelFields: ["class_code", "name", "share_class"]
|
|
2491
|
+
},
|
|
2492
|
+
round: { idFields: ["round_id", "equity_round_id", "id"], labelFields: ["name"] },
|
|
2493
|
+
service_request: {
|
|
2494
|
+
idFields: ["request_id", "service_request_id", "id"],
|
|
2495
|
+
labelFields: ["service_slug", "status"]
|
|
2496
|
+
}
|
|
2497
|
+
};
|
|
2498
|
+
const spec = specs[kind];
|
|
2499
|
+
const id = extractId(record, spec.idFields);
|
|
2500
|
+
if (!id) {
|
|
2501
|
+
return null;
|
|
2502
|
+
}
|
|
2503
|
+
const labels = spec.labelFields.map((field) => record[field]).filter((value) => typeof value === "string" && value.trim().length > 0);
|
|
2504
|
+
const persistedHandle = typeof record.handle === "string" && record.handle.trim().length > 0 ? record.handle.trim() : void 0;
|
|
2505
|
+
let label = labels[0] ?? id;
|
|
2506
|
+
if (kind === "share_transfer") {
|
|
2507
|
+
const fromHolder = typeof record.from_holder === "string" ? record.from_holder.trim() : "";
|
|
2508
|
+
const toHolder = typeof record.to_holder === "string" ? record.to_holder.trim() : "";
|
|
2509
|
+
const transferType = typeof record.transfer_type === "string" ? record.transfer_type.trim() : "";
|
|
2510
|
+
const composite = [
|
|
2511
|
+
fromHolder && toHolder ? `${fromHolder}-to-${toHolder}` : "",
|
|
2512
|
+
transferType
|
|
2513
|
+
].filter(Boolean).join("-");
|
|
2514
|
+
if (composite) {
|
|
2515
|
+
label = composite;
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
return {
|
|
2519
|
+
id,
|
|
2520
|
+
label,
|
|
2521
|
+
tokens: uniqueStrings([id, persistedHandle, ...labels]),
|
|
2522
|
+
raw: record
|
|
2523
|
+
};
|
|
2524
|
+
}
|
|
2525
|
+
function getReferenceId(kind, record) {
|
|
2526
|
+
return describeReferenceRecord(kind, record)?.id;
|
|
2527
|
+
}
|
|
2528
|
+
function getReferenceLabel(kind, record) {
|
|
2529
|
+
return describeReferenceRecord(kind, record)?.label;
|
|
2530
|
+
}
|
|
2531
|
+
function getReferenceAlias(kind, record) {
|
|
2532
|
+
if (typeof record.handle === "string" && record.handle.trim().length > 0) {
|
|
2533
|
+
return record.handle.trim();
|
|
2534
|
+
}
|
|
2535
|
+
const described = describeReferenceRecord(kind, record);
|
|
2536
|
+
if (!described) return void 0;
|
|
2537
|
+
const alias = slugify(described.label);
|
|
2538
|
+
return alias || shortId(described.id);
|
|
2539
|
+
}
|
|
2540
|
+
function matchRank(record, normalizedQuery) {
|
|
2541
|
+
if (!normalizedQuery || normalizedQuery === "*") {
|
|
2542
|
+
return 5;
|
|
2543
|
+
}
|
|
2544
|
+
if (normalize(record.id) === normalizedQuery) {
|
|
2545
|
+
return 0;
|
|
2546
|
+
}
|
|
2547
|
+
if (record.tokens.has(normalizedQuery)) {
|
|
2548
|
+
return 1;
|
|
2549
|
+
}
|
|
2550
|
+
if (normalize(record.id).startsWith(normalizedQuery)) {
|
|
2551
|
+
return 2;
|
|
2552
|
+
}
|
|
2553
|
+
if (Array.from(record.tokens).some((token) => token.startsWith(normalizedQuery))) {
|
|
2554
|
+
return 3;
|
|
2555
|
+
}
|
|
2556
|
+
return 4;
|
|
2557
|
+
}
|
|
2558
|
+
var ReferenceTracker = class {
|
|
2559
|
+
constructor(storage) {
|
|
2560
|
+
this.storage = storage;
|
|
2561
|
+
}
|
|
2562
|
+
/** Remember a reference for @last reuse. */
|
|
2563
|
+
remember(kind, id, entityId) {
|
|
2564
|
+
this.storage.setLastReference(kind, id, entityId);
|
|
2565
|
+
}
|
|
2566
|
+
/** Resolve @last / @last:kind references. */
|
|
2567
|
+
resolveLastReference(ref, kind, entityId) {
|
|
2568
|
+
const parsed = parseLastReference(ref);
|
|
2569
|
+
if (!parsed.isLast) return parsed;
|
|
2570
|
+
const lastKind = parsed.kind ?? kind;
|
|
2571
|
+
if (lastKind !== kind) {
|
|
2572
|
+
throw new Error(
|
|
2573
|
+
`@last:${lastKind} cannot be used where a ${kindLabel(kind)} reference is required.`
|
|
2574
|
+
);
|
|
2575
|
+
}
|
|
2576
|
+
const id = this.storage.getLastReference(lastKind, entityId);
|
|
2577
|
+
return { ...parsed, id };
|
|
2578
|
+
}
|
|
2579
|
+
/** Find the single best match for a query against a list of records. */
|
|
2580
|
+
findBestMatch(kind, query, records) {
|
|
2581
|
+
const matches = this.findMatches(kind, query, records);
|
|
2582
|
+
return matches.length > 0 ? matches[0] : null;
|
|
2583
|
+
}
|
|
2584
|
+
/** Find all matching records ranked by relevance. */
|
|
2585
|
+
findMatches(kind, query, records) {
|
|
2586
|
+
const trimmedQuery = validateReferenceInput(query, "query", { allowEmpty: true });
|
|
2587
|
+
const described = records.map((record) => describeReferenceRecord(kind, record)).filter((record) => record !== null);
|
|
2588
|
+
const normalizedQuery = normalize(trimmedQuery);
|
|
2589
|
+
const matches = described.filter((record) => {
|
|
2590
|
+
if (!normalizedQuery || normalizedQuery === "*") {
|
|
2591
|
+
return true;
|
|
2592
|
+
}
|
|
2593
|
+
if (normalize(record.id).startsWith(normalizedQuery)) {
|
|
2594
|
+
return true;
|
|
2595
|
+
}
|
|
2596
|
+
if (record.tokens.has(normalizedQuery)) {
|
|
2597
|
+
return true;
|
|
2598
|
+
}
|
|
2599
|
+
return Array.from(record.tokens).some((token) => token.includes(normalizedQuery));
|
|
2600
|
+
}).sort(
|
|
2601
|
+
(left, right) => matchRank(left, normalizedQuery) - matchRank(right, normalizedQuery) || left.label.localeCompare(right.label) || left.id.localeCompare(right.id)
|
|
2602
|
+
);
|
|
2603
|
+
return matches.map((record) => ({
|
|
2604
|
+
kind,
|
|
2605
|
+
id: record.id,
|
|
2606
|
+
short_id: shortId(record.id),
|
|
2607
|
+
label: record.label,
|
|
2608
|
+
alias: getReferenceAlias(kind, record.raw),
|
|
2609
|
+
raw: record.raw
|
|
2610
|
+
}));
|
|
2611
|
+
}
|
|
2612
|
+
};
|
|
2613
|
+
|
|
2614
|
+
// src/workflows/equity-helpers.ts
|
|
2615
|
+
function normalizedGrantType2(grantType) {
|
|
2616
|
+
return grantType.trim().toLowerCase().replaceAll("-", "_").replaceAll(" ", "_");
|
|
2617
|
+
}
|
|
2618
|
+
function expectedInstrumentKinds2(grantType) {
|
|
2619
|
+
switch (normalizedGrantType2(grantType)) {
|
|
2620
|
+
case "common":
|
|
2621
|
+
case "common_stock":
|
|
2622
|
+
return ["common_equity"];
|
|
2623
|
+
case "preferred":
|
|
2624
|
+
case "preferred_stock":
|
|
2625
|
+
return ["preferred_equity"];
|
|
2626
|
+
case "unit":
|
|
2627
|
+
case "membership_unit":
|
|
2628
|
+
return ["membership_unit"];
|
|
2629
|
+
case "option":
|
|
2630
|
+
case "options":
|
|
2631
|
+
case "stock_option":
|
|
2632
|
+
case "iso":
|
|
2633
|
+
case "nso":
|
|
2634
|
+
return ["option_grant"];
|
|
2635
|
+
case "rsa":
|
|
2636
|
+
return ["common_equity", "preferred_equity"];
|
|
2637
|
+
default:
|
|
2638
|
+
return [];
|
|
2639
|
+
}
|
|
2640
|
+
}
|
|
2641
|
+
function grantRequiresCurrent409a2(grantType, instrumentKind) {
|
|
2642
|
+
return instrumentKind?.toLowerCase() === "option_grant" || expectedInstrumentKinds2(grantType).includes("option_grant");
|
|
2643
|
+
}
|
|
2644
|
+
function buildInstrumentCreationHint(grantType) {
|
|
2645
|
+
const normalized = normalizedGrantType2(grantType);
|
|
2646
|
+
switch (normalized) {
|
|
2647
|
+
case "preferred":
|
|
2648
|
+
case "preferred_stock":
|
|
2649
|
+
return "Create one with: corp cap-table create-instrument --kind preferred_equity --symbol SERIES-A --authorized-units <shares>";
|
|
2650
|
+
case "option":
|
|
2651
|
+
case "options":
|
|
2652
|
+
case "stock_option":
|
|
2653
|
+
case "iso":
|
|
2654
|
+
case "nso":
|
|
2655
|
+
return "Create one with: corp cap-table create-instrument --kind option_grant --symbol OPTION-PLAN --authorized-units <shares>";
|
|
2656
|
+
case "membership_unit":
|
|
2657
|
+
case "unit":
|
|
2658
|
+
return "Create one with: corp cap-table create-instrument --kind membership_unit --symbol UNIT --authorized-units <units>";
|
|
2659
|
+
case "common":
|
|
2660
|
+
case "common_stock":
|
|
2661
|
+
return "Create one with: corp cap-table create-instrument --kind common_equity --symbol COMMON --authorized-units <shares>";
|
|
2662
|
+
default:
|
|
2663
|
+
return "Create a matching instrument first, then pass --instrument-id explicitly.";
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
function resolveInstrumentForGrant2(instruments, grantType, explicitInstrumentId) {
|
|
2667
|
+
if (explicitInstrumentId) {
|
|
2668
|
+
const explicit = instruments.find(
|
|
2669
|
+
(instrument) => instrument.instrument_id === explicitInstrumentId
|
|
2670
|
+
);
|
|
2671
|
+
if (!explicit) {
|
|
2672
|
+
throw new Error(
|
|
2673
|
+
`Instrument ${explicitInstrumentId} was not found on the cap table.`
|
|
2674
|
+
);
|
|
2675
|
+
}
|
|
2676
|
+
return explicit;
|
|
2677
|
+
}
|
|
2678
|
+
const kinds = expectedInstrumentKinds2(grantType);
|
|
2679
|
+
if (kinds.length === 0) {
|
|
2680
|
+
throw new Error(
|
|
2681
|
+
`No default instrument mapping exists for grant type "${grantType}". ${buildInstrumentCreationHint(grantType)}`
|
|
2682
|
+
);
|
|
2683
|
+
}
|
|
2684
|
+
const match = instruments.find(
|
|
2685
|
+
(instrument) => kinds.includes(String(instrument.kind).toLowerCase())
|
|
2686
|
+
);
|
|
2687
|
+
if (!match) {
|
|
2688
|
+
throw new Error(
|
|
2689
|
+
`No instrument found for grant type "${grantType}". Expected one of: ${kinds.join(", ")}. ${buildInstrumentCreationHint(grantType)}`
|
|
2690
|
+
);
|
|
2691
|
+
}
|
|
2692
|
+
return match;
|
|
2693
|
+
}
|
|
2694
|
+
async function entityHasActiveBoard2(client, entityId) {
|
|
2695
|
+
const bodies = await client.listGovernanceBodies(entityId);
|
|
2696
|
+
return bodies.some(
|
|
2697
|
+
(body) => String(body.body_type ?? "").toLowerCase() === "board_of_directors" && String(body.status ?? "active").toLowerCase() === "active"
|
|
2698
|
+
);
|
|
2699
|
+
}
|
|
2700
|
+
async function ensureIssuancePreflight2(client, entityId, grantType, instrument, meetingId, resolutionId, operationLabel) {
|
|
2701
|
+
if (!meetingId || !resolutionId) {
|
|
2702
|
+
if (await entityHasActiveBoard2(client, entityId)) {
|
|
2703
|
+
const label = operationLabel ?? "this issuance";
|
|
2704
|
+
throw new Error(
|
|
2705
|
+
`Board approval is required for ${label}. Pass --meeting-id and --resolution-id from a passed board vote.
|
|
2706
|
+
Tip: Use 'corp governance quick-approve --text "RESOLVED: authorize ${label}"' for one-step approval.`
|
|
2707
|
+
);
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
if (!grantRequiresCurrent409a2(grantType, instrument?.kind)) {
|
|
2711
|
+
return;
|
|
2712
|
+
}
|
|
2713
|
+
try {
|
|
2714
|
+
await client.getCurrent409a(entityId);
|
|
2715
|
+
} catch (err) {
|
|
2716
|
+
const msg = String(err);
|
|
2717
|
+
if (msg.includes("404") || msg.includes("Not found") || msg.includes("not found")) {
|
|
2718
|
+
throw new Error(
|
|
2719
|
+
"Stock option issuances require a current approved 409A valuation. Create and approve one first with: corp cap-table create-valuation --type four_oh_nine_a --date YYYY-MM-DD --methodology <method>; corp cap-table submit-valuation <valuation-ref>; corp cap-table approve-valuation <valuation-ref> --resolution-id <resolution-ref>"
|
|
2720
|
+
);
|
|
2721
|
+
}
|
|
2722
|
+
throw err;
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
|
|
2726
|
+
// src/workflows/issue-equity.ts
|
|
2727
|
+
async function issueEquity(client, args) {
|
|
2728
|
+
const steps = [];
|
|
2729
|
+
try {
|
|
2730
|
+
const capTable = await client.getCapTable(args.entityId);
|
|
2731
|
+
const issuerLegalEntityId = capTable.issuer_legal_entity_id;
|
|
2732
|
+
if (!issuerLegalEntityId) {
|
|
2733
|
+
return {
|
|
2734
|
+
success: false,
|
|
2735
|
+
error: "No issuer legal entity found. Has this entity been formed with a cap table?",
|
|
2736
|
+
steps
|
|
2737
|
+
};
|
|
2738
|
+
}
|
|
2739
|
+
const instruments = capTable.instruments ?? [];
|
|
2740
|
+
if (!instruments.length) {
|
|
2741
|
+
return {
|
|
2742
|
+
success: false,
|
|
2743
|
+
error: "No instruments found on cap table. Create one with: corp cap-table create-instrument --kind common_equity --symbol COMMON --authorized-units <shares>",
|
|
2744
|
+
steps
|
|
2745
|
+
};
|
|
2746
|
+
}
|
|
2747
|
+
const instrument = resolveInstrumentForGrant2(
|
|
2748
|
+
instruments,
|
|
2749
|
+
args.grantType,
|
|
2750
|
+
args.instrumentId
|
|
2751
|
+
);
|
|
2752
|
+
const instrumentId = instrument.instrument_id;
|
|
2753
|
+
steps.push({
|
|
2754
|
+
name: "resolve_instrument",
|
|
2755
|
+
status: "ok",
|
|
2756
|
+
data: {
|
|
2757
|
+
instrument_id: instrumentId,
|
|
2758
|
+
symbol: instrument.symbol,
|
|
2759
|
+
kind: instrument.kind
|
|
2760
|
+
},
|
|
2761
|
+
detail: `Using instrument: ${instrument.symbol} (${instrument.kind})`
|
|
2762
|
+
});
|
|
2763
|
+
await ensureIssuancePreflight2(
|
|
2764
|
+
client,
|
|
2765
|
+
args.entityId,
|
|
2766
|
+
args.grantType,
|
|
2767
|
+
instrument,
|
|
2768
|
+
args.meetingId,
|
|
2769
|
+
args.resolutionId,
|
|
2770
|
+
"equity issuance"
|
|
2771
|
+
);
|
|
2772
|
+
steps.push({ name: "preflight", status: "ok" });
|
|
2773
|
+
const round = await client.startEquityRound({
|
|
2774
|
+
entity_id: args.entityId,
|
|
2775
|
+
name: `${args.grantType} grant \u2014 ${args.recipientName}`,
|
|
2776
|
+
issuer_legal_entity_id: issuerLegalEntityId
|
|
2777
|
+
});
|
|
2778
|
+
const roundId = round.round_id ?? round.equity_round_id;
|
|
2779
|
+
steps.push({
|
|
2780
|
+
name: "start_round",
|
|
2781
|
+
status: "ok",
|
|
2782
|
+
data: { round_id: roundId }
|
|
2783
|
+
});
|
|
2784
|
+
const securityData = {
|
|
2785
|
+
entity_id: args.entityId,
|
|
2786
|
+
instrument_id: instrumentId,
|
|
2787
|
+
quantity: args.shares,
|
|
2788
|
+
recipient_name: args.recipientName,
|
|
2789
|
+
grant_type: args.grantType
|
|
2790
|
+
};
|
|
2791
|
+
if (args.recipientEmail) securityData.email = args.recipientEmail;
|
|
2792
|
+
const existingHolders = capTable.holders ?? [];
|
|
2793
|
+
const matchingHolder = existingHolders.find((h) => {
|
|
2794
|
+
const nameMatch = String(h.name ?? "").toLowerCase() === args.recipientName.toLowerCase();
|
|
2795
|
+
const emailMatch = args.recipientEmail && String(h.email ?? "").toLowerCase() === args.recipientEmail.toLowerCase();
|
|
2796
|
+
return nameMatch || emailMatch;
|
|
2797
|
+
});
|
|
2798
|
+
if (matchingHolder) {
|
|
2799
|
+
const holderId = matchingHolder.holder_id ?? matchingHolder.contact_id ?? matchingHolder.id;
|
|
2800
|
+
if (holderId) securityData.holder_id = holderId;
|
|
2801
|
+
}
|
|
2802
|
+
await client.addRoundSecurity(roundId, securityData);
|
|
2803
|
+
steps.push({ name: "add_security", status: "ok" });
|
|
2804
|
+
const issuePayload = {
|
|
2805
|
+
entity_id: args.entityId
|
|
2806
|
+
};
|
|
2807
|
+
if (args.meetingId) issuePayload.meeting_id = args.meetingId;
|
|
2808
|
+
if (args.resolutionId) issuePayload.resolution_id = args.resolutionId;
|
|
2809
|
+
const result = await client.issueRound(roundId, issuePayload);
|
|
2810
|
+
steps.push({ name: "issue_round", status: "ok" });
|
|
2811
|
+
return {
|
|
2812
|
+
success: true,
|
|
2813
|
+
data: {
|
|
2814
|
+
...result,
|
|
2815
|
+
round_id: roundId,
|
|
2816
|
+
round,
|
|
2817
|
+
shares: args.shares,
|
|
2818
|
+
grant_type: args.grantType,
|
|
2819
|
+
recipient: args.recipientName
|
|
2820
|
+
},
|
|
2821
|
+
steps
|
|
2822
|
+
};
|
|
2823
|
+
} catch (err) {
|
|
2824
|
+
steps.push({
|
|
2825
|
+
name: "error",
|
|
2826
|
+
status: "failed",
|
|
2827
|
+
detail: String(err)
|
|
2828
|
+
});
|
|
2829
|
+
return {
|
|
2830
|
+
success: false,
|
|
2831
|
+
error: err instanceof Error ? err.message : String(err),
|
|
2832
|
+
steps
|
|
2833
|
+
};
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
|
|
2837
|
+
// src/workflows/issue-safe.ts
|
|
2838
|
+
async function issueSafe(client, args) {
|
|
2839
|
+
const steps = [];
|
|
2840
|
+
const safeType = args.safeType ?? "post_money";
|
|
2841
|
+
try {
|
|
2842
|
+
await ensureIssuancePreflight2(
|
|
2843
|
+
client,
|
|
2844
|
+
args.entityId,
|
|
2845
|
+
safeType,
|
|
2846
|
+
void 0,
|
|
2847
|
+
args.meetingId,
|
|
2848
|
+
args.resolutionId,
|
|
2849
|
+
"SAFE issuance"
|
|
2850
|
+
);
|
|
2851
|
+
steps.push({ name: "preflight", status: "ok" });
|
|
2852
|
+
const body = {
|
|
2853
|
+
entity_id: args.entityId,
|
|
2854
|
+
investor_name: args.investorName,
|
|
2855
|
+
principal_amount_cents: args.amountCents,
|
|
2856
|
+
valuation_cap_cents: args.valuationCapCents,
|
|
2857
|
+
safe_type: safeType
|
|
2858
|
+
};
|
|
2859
|
+
if (args.email) body.email = args.email;
|
|
2860
|
+
if (args.meetingId) body.meeting_id = args.meetingId;
|
|
2861
|
+
if (args.resolutionId) body.resolution_id = args.resolutionId;
|
|
2862
|
+
const result = await client.createSafeNote(body);
|
|
2863
|
+
steps.push({ name: "create_safe", status: "ok" });
|
|
2864
|
+
return {
|
|
2865
|
+
success: true,
|
|
2866
|
+
data: {
|
|
2867
|
+
...result,
|
|
2868
|
+
investor_name: args.investorName,
|
|
2869
|
+
amount_cents: args.amountCents,
|
|
2870
|
+
valuation_cap_cents: args.valuationCapCents
|
|
2871
|
+
},
|
|
2872
|
+
steps
|
|
2873
|
+
};
|
|
2874
|
+
} catch (err) {
|
|
2875
|
+
steps.push({
|
|
2876
|
+
name: "error",
|
|
2877
|
+
status: "failed",
|
|
2878
|
+
detail: String(err)
|
|
2879
|
+
});
|
|
2880
|
+
return {
|
|
2881
|
+
success: false,
|
|
2882
|
+
error: err instanceof Error ? err.message : String(err),
|
|
2883
|
+
steps
|
|
2884
|
+
};
|
|
2885
|
+
}
|
|
2886
|
+
}
|
|
2887
|
+
|
|
2888
|
+
// src/workflows/written-consent.ts
|
|
2889
|
+
async function writtenConsent(client, args) {
|
|
2890
|
+
const steps = [];
|
|
2891
|
+
try {
|
|
2892
|
+
const payload = {
|
|
2893
|
+
entity_id: args.entityId,
|
|
2894
|
+
body_id: args.bodyId,
|
|
2895
|
+
title: args.title,
|
|
2896
|
+
description: args.description
|
|
2897
|
+
};
|
|
2898
|
+
const result = await client.writtenConsent(payload);
|
|
2899
|
+
const meetingId = String(result.meeting_id ?? "");
|
|
2900
|
+
steps.push({
|
|
2901
|
+
name: "create_written_consent",
|
|
2902
|
+
status: "ok",
|
|
2903
|
+
data: { meeting_id: meetingId || void 0 }
|
|
2904
|
+
});
|
|
2905
|
+
if (meetingId) {
|
|
2906
|
+
try {
|
|
2907
|
+
const seats = await client.getGovernanceSeats(
|
|
2908
|
+
args.bodyId,
|
|
2909
|
+
args.entityId
|
|
2910
|
+
);
|
|
2911
|
+
const seatIds = seats.map(
|
|
2912
|
+
(s) => String(
|
|
2913
|
+
s.seat_id ?? s.id ?? ""
|
|
2914
|
+
)
|
|
2915
|
+
).filter((id) => id.length > 0);
|
|
2916
|
+
if (seatIds.length > 0) {
|
|
2917
|
+
await client.conveneMeeting(meetingId, args.entityId, {
|
|
2918
|
+
present_seat_ids: seatIds
|
|
2919
|
+
});
|
|
2920
|
+
steps.push({
|
|
2921
|
+
name: "auto_open",
|
|
2922
|
+
status: "ok",
|
|
2923
|
+
data: { seat_count: seatIds.length },
|
|
2924
|
+
detail: `Opened with ${seatIds.length} seat(s) present`
|
|
2925
|
+
});
|
|
2926
|
+
} else {
|
|
2927
|
+
steps.push({
|
|
2928
|
+
name: "auto_open",
|
|
2929
|
+
status: "skipped",
|
|
2930
|
+
detail: "No seats found on body"
|
|
2931
|
+
});
|
|
2932
|
+
}
|
|
2933
|
+
} catch {
|
|
2934
|
+
steps.push({
|
|
2935
|
+
name: "auto_open",
|
|
2936
|
+
status: "skipped",
|
|
2937
|
+
detail: "Failed to auto-open meeting (non-fatal)"
|
|
2938
|
+
});
|
|
2939
|
+
}
|
|
2940
|
+
} else {
|
|
2941
|
+
steps.push({
|
|
2942
|
+
name: "auto_open",
|
|
2943
|
+
status: "skipped",
|
|
2944
|
+
detail: "No meeting_id returned"
|
|
2945
|
+
});
|
|
2946
|
+
}
|
|
2947
|
+
return {
|
|
2948
|
+
success: true,
|
|
2949
|
+
data: { ...result, meeting_id: meetingId || void 0 },
|
|
2950
|
+
steps
|
|
2951
|
+
};
|
|
2952
|
+
} catch (err) {
|
|
2953
|
+
steps.push({
|
|
2954
|
+
name: "error",
|
|
2955
|
+
status: "failed",
|
|
2956
|
+
detail: String(err)
|
|
2957
|
+
});
|
|
2958
|
+
return {
|
|
2959
|
+
success: false,
|
|
2960
|
+
error: err instanceof Error ? err.message : String(err),
|
|
2961
|
+
steps
|
|
2962
|
+
};
|
|
2963
|
+
}
|
|
2964
|
+
}
|
|
2301
2965
|
export {
|
|
2302
2966
|
AccountType,
|
|
2303
2967
|
AgendaItemStatus,
|
|
@@ -2366,10 +3030,12 @@ export {
|
|
|
2366
3030
|
QuorumStatus,
|
|
2367
3031
|
QuorumThreshold,
|
|
2368
3032
|
READ_ONLY_TOOLS,
|
|
3033
|
+
RESOURCE_KINDS,
|
|
2369
3034
|
ReceiptStatus,
|
|
2370
3035
|
ReconciliationStatus,
|
|
2371
3036
|
Recurrence,
|
|
2372
3037
|
ReferenceKind,
|
|
3038
|
+
ReferenceTracker,
|
|
2373
3039
|
ResolutionType,
|
|
2374
3040
|
RiskLevel,
|
|
2375
3041
|
SYSTEM_PROMPT_BASE,
|
|
@@ -2396,18 +3062,45 @@ export {
|
|
|
2396
3062
|
WorkItemActorTypeValue,
|
|
2397
3063
|
WorkItemStatus,
|
|
2398
3064
|
WorkflowType,
|
|
3065
|
+
buildInstrumentCreationHint,
|
|
3066
|
+
describeReferenceRecord,
|
|
2399
3067
|
describeToolCall,
|
|
2400
3068
|
ensureEnvFile,
|
|
3069
|
+
ensureIssuancePreflight2 as ensureIssuancePreflight,
|
|
2401
3070
|
ensureSafeInstrument,
|
|
3071
|
+
entityHasActiveBoard2 as entityHasActiveBoard,
|
|
2402
3072
|
executeTool,
|
|
3073
|
+
expectedInstrumentKinds2 as expectedInstrumentKinds,
|
|
3074
|
+
extractId,
|
|
2403
3075
|
formatConfigSection,
|
|
2404
3076
|
generateFernetKey,
|
|
2405
3077
|
generateSecret,
|
|
3078
|
+
getReferenceAlias,
|
|
3079
|
+
getReferenceId,
|
|
3080
|
+
getReferenceLabel,
|
|
3081
|
+
grantRequiresCurrent409a2 as grantRequiresCurrent409a,
|
|
3082
|
+
isEntityScopedKind,
|
|
3083
|
+
isOpaqueUuid,
|
|
3084
|
+
isShortIdCandidate,
|
|
3085
|
+
isValidResourceKind,
|
|
2406
3086
|
isWriteTool,
|
|
3087
|
+
issueEquity,
|
|
3088
|
+
issueSafe,
|
|
3089
|
+
kindLabel,
|
|
2407
3090
|
loadEnvFile,
|
|
3091
|
+
matchRank,
|
|
3092
|
+
normalize,
|
|
3093
|
+
normalizedGrantType2 as normalizedGrantType,
|
|
3094
|
+
parseLastReference,
|
|
2408
3095
|
processRequest,
|
|
2409
3096
|
provisionWorkspace,
|
|
2410
3097
|
resetCache,
|
|
2411
|
-
resolveBinaryPath
|
|
3098
|
+
resolveBinaryPath,
|
|
3099
|
+
resolveInstrumentForGrant2 as resolveInstrumentForGrant,
|
|
3100
|
+
shortId,
|
|
3101
|
+
slugify,
|
|
3102
|
+
uniqueStrings,
|
|
3103
|
+
validateReferenceInput,
|
|
3104
|
+
writtenConsent
|
|
2412
3105
|
};
|
|
2413
3106
|
//# sourceMappingURL=index.js.map
|