@thecorporation/corp-tools 26.3.45 → 26.3.47

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/index.d.ts CHANGED
@@ -1,3 +1,9 @@
1
+ type CapTableInstrument = {
2
+ instrument_id: string;
3
+ kind: string;
4
+ symbol: string;
5
+ status?: string;
6
+ };
1
7
  interface CorpConfig {
2
8
  api_url: string;
3
9
  api_key: string;
@@ -3419,14 +3425,9 @@ interface ToolContext {
3419
3425
  dataDir: string;
3420
3426
  onEntityFormed?: (entityId: string) => void;
3421
3427
  }
3422
- type CapTableInstrument = {
3423
- instrument_id: string;
3424
- kind: string;
3425
- symbol: string;
3426
- status?: string;
3427
- };
3428
3428
  declare function ensureSafeInstrument(client: CorpAPIClient, entityId: string): Promise<CapTableInstrument>;
3429
3429
  declare const TOOL_DEFINITIONS: Record<string, unknown>[];
3430
+ declare const TOOL_DISPATCH_COUNT: number;
3430
3431
  declare function isWriteTool(name: string, args?: Record<string, unknown>): boolean;
3431
3432
  declare function executeTool(name: string, args: Record<string, unknown>, client: CorpAPIClient, ctx: ToolContext): Promise<string>;
3432
3433
 
@@ -3435,7 +3436,7 @@ declare function describeToolCall(name: string, args: Record<string, unknown>):
3435
3436
  /**
3436
3437
  * System prompt base and config formatter.
3437
3438
  */
3438
- declare const SYSTEM_PROMPT_BASE = "You are a corporate governance assistant for TheCorporation, an agentic corporate governance platform.\n\n## Context\n{context}\n\n## Tools\nYou have 10 tools, each with an `action` parameter that selects the operation:\n\n| Tool | Actions |\n|------|---------|\n| **workspace** | status, list_entities, obligations, billing |\n| **entity** | get_cap_table, list_documents, list_safe_notes, form, create, add_founder, finalize, convert, dissolve |\n| **equity** | start_round, add_security, issue_round, issue, issue_safe, transfer, distribution |\n| **valuation** | create, submit, approve |\n| **meeting** | schedule, notice, convene, vote, resolve, finalize_item, adjourn, cancel, consent, attach_document, list_items, list_votes |\n| **finance** | create_invoice, run_payroll, submit_payment, open_bank_account, reconcile |\n| **compliance** | file_tax, track_deadline, classify_contractor, generate_contract |\n| **document** | signing_link, signer_link, download_link |\n| **checklist** | get, update |\n| **agent** | list, create, message, update, add_skill |\n\n## Rules\n- All monetary values are in integer cents ($1,000 = 100000).\n- Be concise and helpful.\n- **You MUST confirm with the user before calling ANY write action.** Describe what you are about to do and wait for explicit approval. Never execute tools speculatively or \"on behalf of\" the user without their go-ahead.\n- Don't ask for info available in platform config \u2014 use the correct values automatically.\n- If only one option exists for a field, use it without asking.\n- Don't make up data \u2014 only present what the tools return.\n- If a tool returns an error, explain it simply without exposing raw error details.\n- NEVER create an agent to answer a question you can answer yourself. You are the assistant \u2014 answer questions directly using your knowledge and the read tools.\n\n## Agent Rules\n- Agents are for **delegating recurring corporate operations tasks** that the user explicitly requests \u2014 e.g. \"process incoming invoices\", \"monitor compliance deadlines\", \"handle payroll every two weeks\".\n- Agents are NOT for research, answering questions, or one-off lookups. If the user asks a question, YOU answer it.\n- NEVER proactively suggest or create an agent unless the user specifically asks for one.\n- Agent tools require a paid plan.\n\n## Entity Formation Rules\n- **Prefer the staged formation flow** over `entity action=form`:\n 1. `entity action=create` \u2014 type + name \u2192 returns `entity_id`\n 2. `entity action=add_founder` \u2014 add each founder one at a time (name, email, role, ownership_pct)\n 3. `entity action=finalize` \u2014 generates documents + cap table\n- When using `entity action=form` (legacy), you MUST ask about all founding members and their ownership allocations BEFORE calling it.\n- For LLCs, ownership percentages must total 100%.\n\n## Equity Round Rules\n- **Prefer the staged round flow** for issuing equity to multiple holders:\n 1. `equity action=start_round` \u2014 entity_id + name + issuer_legal_entity_id \u2192 returns `round_id`\n 2. `equity action=add_security` \u2014 add each holder's shares one at a time (round_id, instrument_id, quantity, recipient_name, plus holder_id or email)\n 3. `equity action=issue_round` \u2014 creates positions for all pending securities, closes the round, and auto-creates a board meeting agenda item for approval (or adds to an existing pending meeting)\n 4. Complete the board meeting lifecycle (notice \u2192 convene \u2192 vote \u2192 resolve \u2192 finalize \u2192 adjourn) to formally approve the round\n- The entity must already have a cap table with holders and instruments set up.\n- Use `entity action=get_cap_table` to look up holder IDs, instrument IDs, and the issuer legal entity ID before starting.\n- `equity action=add_security` can resolve recipients by `holder_id`, `email`, or auto-create from `recipient_name`.\n\n## Share Transfer Rules\n- **Prefer the transfer workflow** for share transfers \u2014 it includes bylaws review, ROFR, board approval, document generation, and signatures.\n- `equity action=transfer` is a direct bypass that skips all governance. It requires `skip_governance_review: true` to confirm the caller intentionally wants to skip the workflow. Only use it for corrective entries or when the user explicitly requests skipping governance.\n\n## Valuation Rules\n- To create and approve a 409A valuation:\n 1. `valuation action=create` \u2014 type=four_oh_nine_a + effective_date + methodology + fmv_per_share_cents \u2192 valuation_id (Draft)\n 2. `valuation action=submit` \u2014 Draft \u2192 PendingApproval; auto-creates board meeting agenda item (or adds to existing pending meeting)\n 3. Complete the board meeting lifecycle (notice \u2192 convene \u2192 vote \u2192 resolve \u2192 finalize \u2192 adjourn)\n 4. `valuation action=approve` \u2014 PendingApproval \u2192 Approved; pass resolution_id from the board vote\n- 409A valuations auto-expire after 365 days from effective_date\n- When a new 409A is approved, any previous approved 409A is auto-superseded\n\n## Governance Meeting Rules\n- Full meeting lifecycle:\n 1. `meeting action=schedule` \u2014 entity_id + body_id + meeting_type + title + agenda_item_titles \u2192 meeting_id\n 2. `meeting action=notice` \u2014 Draft \u2192 Noticed\n 3. `meeting action=convene` \u2014 present_seat_ids \u2192 quorum check \u2192 Noticed \u2192 Convened\n 4. `meeting action=vote` \u2014 vote on each agenda item (requires Convened + quorum met)\n 5. `meeting action=resolve` \u2014 tally votes \u2192 create Resolution\n 6. `meeting action=finalize_item` \u2014 mark item as Voted (requires resolution), Discussed, Tabled, or Withdrawn\n 7. `meeting action=adjourn` \u2014 Convened \u2192 Adjourned\n- For written consent (no physical meeting): use `meeting action=consent` \u2014 auto-convened, skip notice/convene\n- Use `meeting action=list_items` to get agenda_item_ids after scheduling\n- Use `entity action=get_cap_table` or governance read tools to look up body_id and seat holder IDs\n- `meeting action=cancel` works from Draft or Noticed status only\n\n## Document Signing Rules\n- You CANNOT sign documents on behalf of users. Signing is a human action.\n- Use `document action=signing_link` to generate a signing URL for a document.\n- Present the signing link so users can open it and sign themselves.\n- NEVER attempt to sign, execute, or complete signature actions automatically.\n- The `document action=signing_link` tool does NOT sign anything \u2014 it only returns a URL.\n\n## User Journey\nAfter completing any action, ALWAYS present the logical next step(s) as a\nnumbered list. The user should never wonder \"what now?\" \u2014 guide them forward.\n\nAfter entity formation (staged or legacy):\n1. The `entity action=finalize` (or `entity action=form`) response includes a `document_ids` array. These documents are created immediately \u2014 they are NEVER \"still being generated\" or delayed.\n2. Immediately call `document action=signing_link` for each document ID in the response to get signing URLs.\n3. Present the signing links to the user right away. Do NOT tell the user to \"check back later\" or that documents are \"being prepared\" \u2014 they already exist.\n4. Then: \"Documents signed! Next: apply for an EIN, open a bank account, or issue equity.\"\n\nAfter document generation:\n1. Present signing links immediately \u2014 don't wait for the user to ask.\n2. Use the document IDs from the tool response \u2014 do NOT call `entity action=list_documents` to re-fetch them.\n\nAfter signing:\n1. \"Documents are signed! Next: file for EIN, open a bank account, or add team members.\"\n\nAfter equity issuance:\n1. \"Equity issued! Next: generate the stock certificate for signing, or issue more grants.\"\n\nGeneral pattern:\n- Always end with 1-2 concrete next actions the user can take.\n- Phrase them as questions or suggestions: \"Would you like to [next step]?\"\n- If there are signing obligations, proactively generate and present the signing links.\n- Never just say \"done\" \u2014 always show what comes next.\n\nAfter major actions, use `checklist action=update` to track progress. Use markdown checkbox\nformat (- [x] / - [ ]). Call `checklist action=get` first to see current state, then\nupdate with checked-off items. This helps users see where they are.\n\n{extra_sections}";
3439
+ declare const SYSTEM_PROMPT_BASE: string;
3439
3440
  declare function formatConfigSection(cfgData: Record<string, unknown>): string;
3440
3441
 
3441
3442
  declare const GENERATED_TOOL_DEFINITIONS: Record<string, unknown>[];
@@ -3639,6 +3640,14 @@ type WorkItemStatus = (typeof WorkItemStatus)[number];
3639
3640
  declare const WorkflowType: readonly ["transfer", "fundraising"];
3640
3641
  type WorkflowType = (typeof WorkflowType)[number];
3641
3642
 
3643
+ /**
3644
+ * Generate a Fernet-compatible encryption key.
3645
+ *
3646
+ * Fernet requires a 32-byte key encoded as **standard** base64 (RFC 4648 sec. 4),
3647
+ * which produces exactly 44 characters (including `=` padding).
3648
+ * We use `toString("base64")` (not `base64url`) so the padding is correct
3649
+ * and the key is accepted by Fernet implementations without modification.
3650
+ */
3642
3651
  declare function generateFernetKey(): string;
3643
3652
  declare function generateSecret(length?: number): string;
3644
3653
  declare function loadEnvFile(path: string): void;
@@ -3783,4 +3792,4 @@ interface WrittenConsentArgs {
3783
3792
  }
3784
3793
  declare function writtenConsent(client: CorpAPIClient, args: WrittenConsentArgs): Promise<WorkflowResult>;
3785
3794
 
3786
- export { type AcceptEquityRoundRequest, type AcceptRoundRequest, AccountType, type AddFounderRequest, type AddFounderResponse, type AddSecurityRequest, type AgendaItemResponse, AgendaItemStatus, AgendaItemType, type AgentResponse, AgentStatus, AntiDilutionMethod, type ApiRecord, type ApplyEquityRoundTermsRequest, type ApplyRoundTermsRequest, AssigneeType, type AttachResolutionDocumentRequest, AuthoritySource, AuthorityTier, BankAccountStatus, BankAccountType, type BoardApproveEquityRoundRequest, type BoardApproveRoundRequest, BodyStatus, BodyType, CapTableAccess, CapTableBasis, type CapTableHolderSummary, type CapTableInstrument, type CapTableInstrumentSummary, type CapTableResponse, type CastVoteRequest, ClassificationResult, type ComputeResolutionRequest, ContactCategory, type ContactProfileResponse, type ContactResponse, ContactStatus, ContactType, ContractStatus, ContractTemplateType, ControlType, type ConveneMeetingRequest, type ConvertEntityRequest, CorpAPIClient, type CorpConfig, type CreateAgentRequest, type CreateContactRequest, type CreateEquityRoundRequest, type CreateExecutionIntentRequest, type CreateFormationRequest, type CreatePendingFormationRequest, type CreateRoundRequest, Currency, DeadlineSeverity, DeadlineStatus, type DigestSummary, type DigestTriggerResponse, type DissolveEntityRequest, DistributionStatus, DistributionType, DocumentRequestStatus, type DocumentResponse, DocumentStatus, type DocumentSummary, DocumentType, EntityType, type EquityRoundResponse, EquityRoundStatus, EscalationStatus, type ExecuteRoundConversionRequest, type FinalizeAgendaItemRequest, type FormationGatesResponse, type FormationResponse, FormationState, FormationStatus, type FormationStatusResponse, type FormationWithCapTableResponse, GENERATED_TOOL_DEFINITIONS, GlAccountCode, GovernanceAuditEventType, type GovernanceBodyResponse, GovernanceMode, type GovernanceSeatResponse, GovernanceTriggerSource, GovernanceTriggerType, GoverningDocType, GrantType, HolderType, HttpMethod, IncidentSeverity, IncidentStatus, InstrumentKind, InstrumentStatus, type IntentResponse, IntentStatus, InvestorType, type InvoiceResponse, InvoiceStatus, type IssueEquityArgs, type IssueSafeArgs, type IssueStagedRoundResponse, JournalEntryStatus, type LLMResponse, LegalEntityRole, type MatchRecord, type MeetingResponse, MeetingStatus, MeetingType, MemberRole, NetworkEgress, type NextStepItem, type NextStepsResponse, type NextStepsSummary, type ObligationResponse, ObligationStatus, type ObligationsSummaryResponse, OfficerTitle, PaymentMethod, PaymentStatus, PayrollStatus, type PendingFormationResponse, PositionStatus, type PreviewRoundConversionRequest, type ProcessRequestOptions, QuorumStatus, QuorumThreshold, READ_ONLY_TOOLS, RESOURCE_KINDS, ReceiptStatus, ReconciliationStatus, Recurrence, ReferenceKind, type ReferenceMatch, type ReferenceStorage, ReferenceTracker, type ResolutionResponse, ResolutionType, type ResourceKind, RiskLevel, type RoundResponse, SYSTEM_PROMPT_BASE, SafeStatus, SafeType, type ScheduleMeetingRequest, Scope, SeatRole, SeatStatus, SessionExpiredError, Side, type StartStagedRoundRequest, TOOL_DEFINITIONS, TOOL_REGISTRY, TaxFilingStatus, type ToolCall, type ToolContext, TransactionPacketStatus, TransferStatus, TransferType, TransfereeRights, Transport, type UpdateAgentRequest, type UpdateContactRequest, ValuationMethodology, ValuationStatus, ValuationType, type VoteResponse, VoteValue, VotingMethod, WorkItemActorTypeValue, WorkItemStatus, type WorkflowResult, type WorkflowStep, WorkflowType, type WorkspaceContactSummary, type WorkspaceEntitySummary, type WorkspaceStatusResponse, type WrittenConsentArgs, type WrittenConsentRequest, type WrittenConsentResponse, buildInstrumentCreationHint, describeReferenceRecord, describeToolCall, ensureEnvFile, ensureIssuancePreflight, ensureSafeInstrument, entityHasActiveBoard, executeTool, expectedInstrumentKinds, extractId, formatConfigSection, generateFernetKey, generateSecret, getReferenceAlias, getReferenceId, getReferenceLabel, grantRequiresCurrent409a, isEntityScopedKind, isOpaqueUuid, isShortIdCandidate, isValidResourceKind, isWriteTool, issueEquity, issueSafe, kindLabel, loadEnvFile, matchRank, normalize, normalizedGrantType, parseLastReference, processRequest, provisionWorkspace, resetCache, resolveBinaryPath, resolveInstrumentForGrant, shortId, slugify, uniqueStrings, validateReferenceInput, writtenConsent };
3795
+ export { type AcceptEquityRoundRequest, type AcceptRoundRequest, AccountType, type AddFounderRequest, type AddFounderResponse, type AddSecurityRequest, type AgendaItemResponse, AgendaItemStatus, AgendaItemType, type AgentResponse, AgentStatus, AntiDilutionMethod, type ApiRecord, type ApplyEquityRoundTermsRequest, type ApplyRoundTermsRequest, AssigneeType, type AttachResolutionDocumentRequest, AuthoritySource, AuthorityTier, BankAccountStatus, BankAccountType, type BoardApproveEquityRoundRequest, type BoardApproveRoundRequest, BodyStatus, BodyType, CapTableAccess, CapTableBasis, type CapTableHolderSummary, type CapTableInstrument, type CapTableInstrumentSummary, type CapTableResponse, type CastVoteRequest, ClassificationResult, type ComputeResolutionRequest, ContactCategory, type ContactProfileResponse, type ContactResponse, ContactStatus, ContactType, ContractStatus, ContractTemplateType, ControlType, type ConveneMeetingRequest, type ConvertEntityRequest, CorpAPIClient, type CorpConfig, type CreateAgentRequest, type CreateContactRequest, type CreateEquityRoundRequest, type CreateExecutionIntentRequest, type CreateFormationRequest, type CreatePendingFormationRequest, type CreateRoundRequest, Currency, DeadlineSeverity, DeadlineStatus, type DigestSummary, type DigestTriggerResponse, type DissolveEntityRequest, DistributionStatus, DistributionType, DocumentRequestStatus, type DocumentResponse, DocumentStatus, type DocumentSummary, DocumentType, EntityType, type EquityRoundResponse, EquityRoundStatus, EscalationStatus, type ExecuteRoundConversionRequest, type FinalizeAgendaItemRequest, type FormationGatesResponse, type FormationResponse, FormationState, FormationStatus, type FormationStatusResponse, type FormationWithCapTableResponse, GENERATED_TOOL_DEFINITIONS, GlAccountCode, GovernanceAuditEventType, type GovernanceBodyResponse, GovernanceMode, type GovernanceSeatResponse, GovernanceTriggerSource, GovernanceTriggerType, GoverningDocType, GrantType, HolderType, HttpMethod, IncidentSeverity, IncidentStatus, InstrumentKind, InstrumentStatus, type IntentResponse, IntentStatus, InvestorType, type InvoiceResponse, InvoiceStatus, type IssueEquityArgs, type IssueSafeArgs, type IssueStagedRoundResponse, JournalEntryStatus, type LLMResponse, LegalEntityRole, type MatchRecord, type MeetingResponse, MeetingStatus, MeetingType, MemberRole, NetworkEgress, type NextStepItem, type NextStepsResponse, type NextStepsSummary, type ObligationResponse, ObligationStatus, type ObligationsSummaryResponse, OfficerTitle, PaymentMethod, PaymentStatus, PayrollStatus, type PendingFormationResponse, PositionStatus, type PreviewRoundConversionRequest, type ProcessRequestOptions, QuorumStatus, QuorumThreshold, READ_ONLY_TOOLS, RESOURCE_KINDS, ReceiptStatus, ReconciliationStatus, Recurrence, ReferenceKind, type ReferenceMatch, type ReferenceStorage, ReferenceTracker, type ResolutionResponse, ResolutionType, type ResourceKind, RiskLevel, type RoundResponse, SYSTEM_PROMPT_BASE, SafeStatus, SafeType, type ScheduleMeetingRequest, Scope, SeatRole, SeatStatus, SessionExpiredError, Side, type StartStagedRoundRequest, TOOL_DEFINITIONS, TOOL_DISPATCH_COUNT, TOOL_REGISTRY, TaxFilingStatus, type ToolCall, type ToolContext, TransactionPacketStatus, TransferStatus, TransferType, TransfereeRights, Transport, type UpdateAgentRequest, type UpdateContactRequest, ValuationMethodology, ValuationStatus, ValuationType, type VoteResponse, VoteValue, VotingMethod, WorkItemActorTypeValue, WorkItemStatus, type WorkflowResult, type WorkflowStep, WorkflowType, type WorkspaceContactSummary, type WorkspaceEntitySummary, type WorkspaceStatusResponse, type WrittenConsentArgs, type WrittenConsentRequest, type WrittenConsentResponse, buildInstrumentCreationHint, describeReferenceRecord, describeToolCall, ensureEnvFile, ensureIssuancePreflight, ensureSafeInstrument, entityHasActiveBoard, executeTool, expectedInstrumentKinds, extractId, formatConfigSection, generateFernetKey, generateSecret, getReferenceAlias, getReferenceId, getReferenceLabel, grantRequiresCurrent409a, isEntityScopedKind, isOpaqueUuid, isShortIdCandidate, isValidResourceKind, isWriteTool, issueEquity, issueSafe, kindLabel, loadEnvFile, matchRank, normalize, normalizedGrantType, parseLastReference, processRequest, provisionWorkspace, resetCache, resolveBinaryPath, resolveInstrumentForGrant, shortId, slugify, uniqueStrings, validateReferenceInput, writtenConsent };
package/dist/index.js CHANGED
@@ -39,7 +39,7 @@ INTERNAL_WORKER_TOKEN={{INTERNAL_WORKER_TOKEN}}
39
39
  # MAX_QUEUE_DEPTH=1000
40
40
  `;
41
41
  function generateFernetKey() {
42
- return randomBytes(32).toString("base64url") + "=";
42
+ return randomBytes(32).toString("base64");
43
43
  }
44
44
  function generateSecret(length = 32) {
45
45
  return randomBytes(length).toString("hex");
@@ -1310,6 +1310,141 @@ var GENERATED_TOOL_DEFINITIONS = [
1310
1310
  }
1311
1311
  ];
1312
1312
 
1313
+ // src/workflows/equity-helpers.ts
1314
+ function normalizedGrantType(grantType) {
1315
+ return grantType.trim().toLowerCase().replaceAll("-", "_").replaceAll(" ", "_");
1316
+ }
1317
+ function expectedInstrumentKinds(grantType) {
1318
+ switch (normalizedGrantType(grantType)) {
1319
+ case "common":
1320
+ case "common_stock":
1321
+ return ["common_equity"];
1322
+ case "preferred":
1323
+ case "preferred_stock":
1324
+ return ["preferred_equity"];
1325
+ case "unit":
1326
+ case "membership_unit":
1327
+ return ["membership_unit"];
1328
+ case "option":
1329
+ case "options":
1330
+ case "stock_option":
1331
+ case "iso":
1332
+ case "nso":
1333
+ return ["option_grant"];
1334
+ case "rsa":
1335
+ return ["common_equity", "preferred_equity"];
1336
+ case "safe":
1337
+ case "post_money":
1338
+ case "pre_money":
1339
+ case "mfn":
1340
+ return ["safe"];
1341
+ default:
1342
+ return [];
1343
+ }
1344
+ }
1345
+ function grantRequiresCurrent409a(grantType, instrumentKind) {
1346
+ return instrumentKind?.toLowerCase() === "option_grant" || expectedInstrumentKinds(grantType).includes("option_grant");
1347
+ }
1348
+ function buildInstrumentCreationHint(grantType) {
1349
+ const normalized = normalizedGrantType(grantType);
1350
+ switch (normalized) {
1351
+ case "preferred":
1352
+ case "preferred_stock":
1353
+ return "Create one with: corp cap-table create-instrument --kind preferred_equity --symbol SERIES-A --authorized-units <shares>";
1354
+ case "option":
1355
+ case "options":
1356
+ case "stock_option":
1357
+ case "iso":
1358
+ case "nso":
1359
+ return "Create one with: corp cap-table create-instrument --kind option_grant --symbol OPTION-PLAN --authorized-units <shares>";
1360
+ case "membership_unit":
1361
+ case "unit":
1362
+ return "Create one with: corp cap-table create-instrument --kind membership_unit --symbol UNIT --authorized-units <units>";
1363
+ case "common":
1364
+ case "common_stock":
1365
+ return "Create one with: corp cap-table create-instrument --kind common_equity --symbol COMMON --authorized-units <shares>";
1366
+ default:
1367
+ return "Create a matching instrument first, then pass --instrument-id explicitly.";
1368
+ }
1369
+ }
1370
+ function resolveInstrumentForGrant(instruments, grantType, explicitInstrumentId) {
1371
+ if (explicitInstrumentId) {
1372
+ const explicit = instruments.find(
1373
+ (instrument) => instrument.instrument_id === explicitInstrumentId
1374
+ );
1375
+ if (!explicit) {
1376
+ throw new Error(
1377
+ `Instrument ${explicitInstrumentId} was not found on the cap table.`
1378
+ );
1379
+ }
1380
+ return explicit;
1381
+ }
1382
+ const kinds = expectedInstrumentKinds(grantType);
1383
+ if (kinds.length === 0) {
1384
+ throw new Error(
1385
+ `No default instrument mapping exists for grant type "${grantType}". ${buildInstrumentCreationHint(grantType)}`
1386
+ );
1387
+ }
1388
+ const match = instruments.find(
1389
+ (instrument) => kinds.includes(String(instrument.kind).toLowerCase())
1390
+ );
1391
+ if (!match) {
1392
+ throw new Error(
1393
+ `No instrument found for grant type "${grantType}". Expected one of: ${kinds.join(", ")}. ${buildInstrumentCreationHint(grantType)}`
1394
+ );
1395
+ }
1396
+ return match;
1397
+ }
1398
+ async function entityHasActiveBoard(client, entityId) {
1399
+ const bodies = await client.listGovernanceBodies(entityId);
1400
+ return bodies.some(
1401
+ (body) => String(body.body_type ?? "").toLowerCase() === "board_of_directors" && String(body.status ?? "active").toLowerCase() === "active"
1402
+ );
1403
+ }
1404
+ async function ensureIssuancePreflight(client, entityId, grantType, instrument, meetingId, resolutionId, operationLabel) {
1405
+ if (!meetingId || !resolutionId) {
1406
+ if (await entityHasActiveBoard(client, entityId)) {
1407
+ const label = operationLabel ?? "this issuance";
1408
+ throw new Error(
1409
+ `Board approval is required for ${label}. Pass --meeting-id and --resolution-id from a passed board vote.
1410
+ Tip: Use 'corp governance quick-approve --text "RESOLVED: authorize ${label}"' for one-step approval.`
1411
+ );
1412
+ }
1413
+ }
1414
+ if (!grantRequiresCurrent409a(grantType, instrument?.kind)) {
1415
+ return;
1416
+ }
1417
+ try {
1418
+ await client.getCurrent409a(entityId);
1419
+ } catch (err) {
1420
+ const msg = String(err);
1421
+ if (msg.includes("404") || msg.includes("Not found") || msg.includes("not found")) {
1422
+ try {
1423
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
1424
+ const valuation = await client.createValuation({
1425
+ entity_id: entityId,
1426
+ valuation_type: "four_oh_nine_a",
1427
+ effective_date: today,
1428
+ methodology: "backsolve",
1429
+ fmv_per_share_cents: 1
1430
+ // $0.01 par value — typical early stage
1431
+ });
1432
+ const valuationId = String(valuation.valuation_id ?? "");
1433
+ if (valuationId) {
1434
+ await client.submitValuationForApproval(valuationId, entityId);
1435
+ await client.approveValuation(valuationId, entityId);
1436
+ }
1437
+ return;
1438
+ } catch {
1439
+ }
1440
+ throw new Error(
1441
+ "Stock option issuances require a current approved 409A valuation.\n Auto-creation failed. Create manually:\n corp cap-table create-valuation --type four_oh_nine_a --date YYYY-MM-DD --methodology backsolve --auto-approve"
1442
+ );
1443
+ }
1444
+ throw err;
1445
+ }
1446
+ }
1447
+
1313
1448
  // src/tools.ts
1314
1449
  function requiredString(args, key) {
1315
1450
  const value = args[key];
@@ -1427,102 +1562,6 @@ var entityActions = {
1427
1562
  },
1428
1563
  dissolve: async (args, client) => client.dissolveEntity(requiredString(args, "entity_id"), args)
1429
1564
  };
1430
- function normalizedGrantType(grantType) {
1431
- return grantType.trim().toLowerCase().replaceAll("-", "_").replaceAll(" ", "_");
1432
- }
1433
- function expectedInstrumentKinds(grantType) {
1434
- switch (normalizedGrantType(grantType)) {
1435
- case "common":
1436
- case "common_stock":
1437
- return ["common_equity"];
1438
- case "preferred":
1439
- case "preferred_stock":
1440
- return ["preferred_equity"];
1441
- case "unit":
1442
- case "membership_unit":
1443
- return ["membership_unit"];
1444
- case "option":
1445
- case "options":
1446
- case "stock_option":
1447
- case "iso":
1448
- case "nso":
1449
- return ["option_grant"];
1450
- case "rsa":
1451
- return ["common_equity", "preferred_equity"];
1452
- case "safe":
1453
- case "post_money":
1454
- case "pre_money":
1455
- case "mfn":
1456
- return ["safe"];
1457
- default:
1458
- return [];
1459
- }
1460
- }
1461
- function grantRequiresCurrent409a(grantType, instrumentKind) {
1462
- return instrumentKind?.toLowerCase() === "option_grant" || expectedInstrumentKinds(grantType).includes("option_grant");
1463
- }
1464
- function instrumentCreationHint(grantType) {
1465
- const normalized = normalizedGrantType(grantType);
1466
- switch (normalized) {
1467
- case "preferred":
1468
- case "preferred_stock":
1469
- return "Create a preferred instrument first, then re-run issuance with that instrument ID.";
1470
- case "option":
1471
- case "options":
1472
- case "stock_option":
1473
- case "iso":
1474
- case "nso":
1475
- return "Create an option_grant instrument first, then re-run issuance with that instrument ID.";
1476
- case "membership_unit":
1477
- case "unit":
1478
- return "Create a membership_unit instrument first, then re-run issuance with that instrument ID.";
1479
- default:
1480
- return "Create a matching instrument first, then re-run issuance with that instrument ID.";
1481
- }
1482
- }
1483
- function resolveInstrumentForGrant(instruments, grantType, explicitInstrumentId) {
1484
- if (explicitInstrumentId) {
1485
- const explicit = instruments.find((instrument) => instrument.instrument_id === explicitInstrumentId);
1486
- if (!explicit) {
1487
- throw new Error(`Instrument ${explicitInstrumentId} was not found on the cap table.`);
1488
- }
1489
- return explicit;
1490
- }
1491
- const expectedKinds = expectedInstrumentKinds(grantType);
1492
- if (!expectedKinds.length) {
1493
- throw new Error(`No default instrument mapping exists for grant type "${grantType}". ${instrumentCreationHint(grantType)}`);
1494
- }
1495
- const match = instruments.find((instrument) => expectedKinds.includes(instrument.kind.toLowerCase()));
1496
- if (!match) {
1497
- throw new Error(
1498
- `No instrument found for grant type "${grantType}". Expected one of: ${expectedKinds.join(", ")}. ${instrumentCreationHint(grantType)}`
1499
- );
1500
- }
1501
- return match;
1502
- }
1503
- async function entityHasActiveBoard(client, entityId) {
1504
- const bodies = await client.listGovernanceBodies(entityId);
1505
- return bodies.some(
1506
- (body) => String(body.body_type ?? "").toLowerCase() === "board_of_directors" && String(body.status ?? "active").toLowerCase() === "active"
1507
- );
1508
- }
1509
- async function ensureIssuancePreflight(client, entityId, grantType, instrument, meetingId, resolutionId) {
1510
- if ((!meetingId || !resolutionId) && await entityHasActiveBoard(client, entityId)) {
1511
- throw new Error("Board approval is required before issuing this round. Provide meeting_id and resolution_id from a passed board vote.");
1512
- }
1513
- if (!grantRequiresCurrent409a(grantType, instrument?.kind)) {
1514
- return;
1515
- }
1516
- try {
1517
- await client.getCurrent409a(entityId);
1518
- } catch (err) {
1519
- const msg = String(err);
1520
- if (msg.includes("404")) {
1521
- throw new Error("Stock option issuances require a current approved 409A valuation.");
1522
- }
1523
- throw err;
1524
- }
1525
- }
1526
1565
  async function ensureSafeInstrument(client, entityId) {
1527
1566
  const capTable = await client.getCapTable(entityId);
1528
1567
  const issuerLegalEntityId = capTable.issuer_legal_entity_id;
@@ -1782,24 +1821,11 @@ var documentActions = {
1782
1821
  },
1783
1822
  download_link: async (args, client) => {
1784
1823
  const docId = args.document_id;
1785
- try {
1786
- const resp = await fetch(`${client.apiUrl}/v1/documents/${docId}/request-copy`, {
1787
- method: "POST",
1788
- headers: { Authorization: `Bearer ${client.apiKey}`, "Content-Type": "application/json" },
1789
- body: JSON.stringify({ email: "owner@workspace" })
1790
- });
1791
- if (!resp.ok) throw new Error("request-copy failed");
1792
- const result = await resp.json();
1793
- let downloadUrl = result.download_url ?? "";
1794
- if (downloadUrl.startsWith("/")) downloadUrl = client.apiUrl + downloadUrl;
1795
- return { document_id: docId, download_url: downloadUrl, expires_in: "24 hours" };
1796
- } catch {
1797
- return {
1798
- document_id: docId,
1799
- download_url: `${client.apiUrl}/v1/documents/${docId}/pdf`,
1800
- note: "Use your API key to authenticate the download."
1801
- };
1802
- }
1824
+ return {
1825
+ document_id: docId,
1826
+ download_url: `${client.apiUrl}/v1/documents/${docId}/pdf`,
1827
+ note: "Use your API key to authenticate the download."
1828
+ };
1803
1829
  },
1804
1830
  preview_pdf: async (args, client) => {
1805
1831
  const entityId = args.entity_id;
@@ -1887,6 +1913,7 @@ var TOOL_DISPATCH = {
1887
1913
  agent: agentActions
1888
1914
  };
1889
1915
  var TOOL_DEFINITIONS = GENERATED_TOOL_DEFINITIONS;
1916
+ var TOOL_DISPATCH_COUNT = Object.keys(TOOL_DISPATCH).length;
1890
1917
  var READ_ONLY_ACTIONS = /* @__PURE__ */ new Set([
1891
1918
  "workspace:status",
1892
1919
  "workspace:list_entities",
@@ -2043,7 +2070,7 @@ var SYSTEM_PROMPT_BASE = `You are a corporate governance assistant for TheCorpor
2043
2070
  {context}
2044
2071
 
2045
2072
  ## Tools
2046
- You have 10 tools, each with an \`action\` parameter that selects the operation:
2073
+ You have ${TOOL_DISPATCH_COUNT} tools, each with an \`action\` parameter that selects the operation:
2047
2074
 
2048
2075
  | Tool | Actions |
2049
2076
  |------|---------|
@@ -2056,6 +2083,7 @@ You have 10 tools, each with an \`action\` parameter that selects the operation:
2056
2083
  | **compliance** | file_tax, track_deadline, classify_contractor, generate_contract |
2057
2084
  | **document** | signing_link, signer_link, download_link |
2058
2085
  | **checklist** | get, update |
2086
+ | **work_item** | list, get, create, claim, complete, release, cancel |
2059
2087
  | **agent** | list, create, message, update, add_skill |
2060
2088
 
2061
2089
  ## Rules
@@ -2611,136 +2639,6 @@ var ReferenceTracker = class {
2611
2639
  }
2612
2640
  };
2613
2641
 
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
- try {
2719
- const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
2720
- const valuation = await client.createValuation({
2721
- entity_id: entityId,
2722
- valuation_type: "four_oh_nine_a",
2723
- effective_date: today,
2724
- methodology: "backsolve",
2725
- fmv_per_share_cents: 1
2726
- // $0.01 par value — typical early stage
2727
- });
2728
- const valuationId = String(valuation.valuation_id ?? "");
2729
- if (valuationId) {
2730
- await client.submitValuationForApproval(valuationId, entityId);
2731
- await client.approveValuation(valuationId, entityId);
2732
- }
2733
- return;
2734
- } catch {
2735
- }
2736
- throw new Error(
2737
- "Stock option issuances require a current approved 409A valuation.\n Auto-creation failed. Create manually:\n corp cap-table create-valuation --type four_oh_nine_a --date YYYY-MM-DD --methodology backsolve --auto-approve"
2738
- );
2739
- }
2740
- throw err;
2741
- }
2742
- }
2743
-
2744
2642
  // src/workflows/issue-equity.ts
2745
2643
  async function issueEquity(client, args) {
2746
2644
  const steps = [];
@@ -2764,13 +2662,13 @@ async function issueEquity(client, args) {
2764
2662
  }
2765
2663
  let instrument;
2766
2664
  try {
2767
- instrument = resolveInstrumentForGrant2(
2665
+ instrument = resolveInstrumentForGrant(
2768
2666
  instruments,
2769
2667
  args.grantType,
2770
2668
  args.instrumentId
2771
2669
  );
2772
2670
  } catch (resolveErr) {
2773
- const kinds = expectedInstrumentKinds2(args.grantType);
2671
+ const kinds = expectedInstrumentKinds(args.grantType);
2774
2672
  if (kinds.includes("option_grant") && !args.instrumentId) {
2775
2673
  const issuerLegalEntityId2 = capTable.issuer_legal_entity_id;
2776
2674
  if (!issuerLegalEntityId2) throw resolveErr;
@@ -2802,7 +2700,7 @@ async function issueEquity(client, args) {
2802
2700
  },
2803
2701
  detail: `Using instrument: ${instrument.symbol} (${instrument.kind})`
2804
2702
  });
2805
- await ensureIssuancePreflight2(
2703
+ await ensureIssuancePreflight(
2806
2704
  client,
2807
2705
  args.entityId,
2808
2706
  args.grantType,
@@ -2881,7 +2779,7 @@ async function issueSafe(client, args) {
2881
2779
  const steps = [];
2882
2780
  const safeType = args.safeType ?? "post_money";
2883
2781
  try {
2884
- await ensureIssuancePreflight2(
2782
+ await ensureIssuancePreflight(
2885
2783
  client,
2886
2784
  args.entityId,
2887
2785
  safeType,
@@ -3089,6 +2987,7 @@ export {
3089
2987
  SessionExpiredError,
3090
2988
  Side,
3091
2989
  TOOL_DEFINITIONS,
2990
+ TOOL_DISPATCH_COUNT,
3092
2991
  TOOL_REGISTRY,
3093
2992
  TaxFilingStatus,
3094
2993
  TransactionPacketStatus,
@@ -3108,11 +3007,11 @@ export {
3108
3007
  describeReferenceRecord,
3109
3008
  describeToolCall,
3110
3009
  ensureEnvFile,
3111
- ensureIssuancePreflight2 as ensureIssuancePreflight,
3010
+ ensureIssuancePreflight,
3112
3011
  ensureSafeInstrument,
3113
- entityHasActiveBoard2 as entityHasActiveBoard,
3012
+ entityHasActiveBoard,
3114
3013
  executeTool,
3115
- expectedInstrumentKinds2 as expectedInstrumentKinds,
3014
+ expectedInstrumentKinds,
3116
3015
  extractId,
3117
3016
  formatConfigSection,
3118
3017
  generateFernetKey,
@@ -3120,7 +3019,7 @@ export {
3120
3019
  getReferenceAlias,
3121
3020
  getReferenceId,
3122
3021
  getReferenceLabel,
3123
- grantRequiresCurrent409a2 as grantRequiresCurrent409a,
3022
+ grantRequiresCurrent409a,
3124
3023
  isEntityScopedKind,
3125
3024
  isOpaqueUuid,
3126
3025
  isShortIdCandidate,
@@ -3132,13 +3031,13 @@ export {
3132
3031
  loadEnvFile,
3133
3032
  matchRank,
3134
3033
  normalize,
3135
- normalizedGrantType2 as normalizedGrantType,
3034
+ normalizedGrantType,
3136
3035
  parseLastReference,
3137
3036
  processRequest,
3138
3037
  provisionWorkspace,
3139
3038
  resetCache,
3140
3039
  resolveBinaryPath,
3141
- resolveInstrumentForGrant2 as resolveInstrumentForGrant,
3040
+ resolveInstrumentForGrant,
3142
3041
  shortId,
3143
3042
  slugify,
3144
3043
  uniqueStrings,