From 44f5d633fe7b19251aeee381897d14d1f5c221bc Mon Sep 17 00:00:00 2001 From: emil07770 Date: Thu, 28 May 2026 20:08:03 +0000 Subject: [PATCH] feat(cli): implement build entity pack list and pack info --- packages/cli/src/commands/entity.ts | 197 +++++++--------------------- 1 file changed, 46 insertions(+), 151 deletions(-) diff --git a/packages/cli/src/commands/entity.ts b/packages/cli/src/commands/entity.ts index 91823b6f..a696941d 100644 --- a/packages/cli/src/commands/entity.ts +++ b/packages/cli/src/commands/entity.ts @@ -1,176 +1,71 @@ import { Command } from 'commander'; import kleur from 'kleur'; +import type { JurisdictionDescribe } from '@profullstack/sh1pt-core'; -// `sh1pt entity` — auxiliary command for entity-ops (formation + name +const KNOWN_PACKS = [ + 'au', 'bb', 'bw', 'ca', 'dao-wy', 'fj', 'gh', 'hk', + 'ie', 'in', 'jm', 'ke', 'my', 'ng', 'nz', 'pk', + 'sg', 'tt', 'tz', 'ug', 'uk', 'us', 'za', 'zm', 'zw', +] as const; + +// `sh1pt entity` — auxiliary command for entity-ops (formation + name // checks + doc generation + filing handoff + compliance tracking). // Cross-cuts the 4 primary verbs so it lives top-level alongside // login/secret/config. Packs live under packages/entity/* and implement // the JurisdictionPack interface in @profullstack/sh1pt-core. - export const entityCmd = new Command('entity') - .description('Entity operations — formation, compliance, spinouts (uses jurisdiction packs)') + .description('Entity operations — formation, compliance, spinouts (uses jurisdiction packs)') .action(() => { entityCmd.help(); }); // ---- pack ------------------------------------------------------------ - const packCmd = entityCmd .command('pack') - .description('Jurisdiction pack registry — list, inspect support level') + .description('Jurisdiction pack registry — list, inspect support level') .action(() => { packCmd.help(); }); packCmd .command('list') .description('List all installed jurisdiction packs with support levels') .option('--json') - .action((opts: { json?: boolean }) => { - if (opts.json) { console.log(JSON.stringify({ packs: [] }, null, 2)); return; } - console.log(kleur.dim('[stub] entity pack list — enumerate registered JurisdictionPacks')); + .action(async (opts: { json?: boolean }) => { + const results: JurisdictionDescribe[] = []; + for (const code of KNOWN_PACKS) { + try { + const m = await import(`@profullstack/sh1pt-entity-${code}`); + results.push((m.default as any).describe()); + } catch { /* pack not installed */ } + } + if (opts.json) { console.log(JSON.stringify({ packs: results }, null, 2)); return; } + if (!results.length) { console.log(kleur.dim('no entity packs installed')); return; } + const C1 = 12, C2 = 14; + console.log(kleur.bold('CODE'.padEnd(C1) + 'SUPPORT'.padEnd(C2) + 'ENTITY TYPES')); + console.log('─'.repeat(70)); + for (const d of results) { + const lc = d.supportLevel === 'full' ? kleur.green : d.supportLevel === 'assisted' ? kleur.yellow : kleur.dim; + console.log(kleur.cyan(d.jurisdictionCode.padEnd(C1)) + lc(d.supportLevel.padEnd(C2)) + kleur.dim((d.entityTypesSupported ?? []).join(', '))); + } + console.log(kleur.dim(`\n${results.length} pack(s) installed`)); }); packCmd .command('info ') .description('Show support level, entity types, filing modes for a pack (e.g. us, nz, uk)') - .action((pack: string) => { - console.log(kleur.cyan(`[stub] entity pack info ${pack}`)); - }); - -// ---- init / compare -------------------------------------------------- - -entityCmd - .command('init ') - .description('Initialise an entity workspace (./entities//)') - .option('--parent ', 'parent entity (studio / holdco)') - .option('--jurisdiction ', 'jurisdiction pack code (us-delaware, nz, uk, hk, au, …)') - .option('--type ', 'entity type (c-corp, llc, limited-company, private-company, …)') - .option('--project ', 'originating project slug (for spinouts)') - .action((slug: string, opts: { parent?: string; jurisdiction?: string; type?: string; project?: string }) => { - console.log(kleur.green(`[stub] entity init ${slug}`) + kleur.dim(` · parent=${opts.parent ?? '-'} jurisdiction=${opts.jurisdiction ?? '-'} type=${opts.type ?? '-'} project=${opts.project ?? '-'}`)); - }); - -entityCmd - .command('compare') - .description('Compare jurisdictions side-by-side (support level, costs, manual steps)') - .requiredOption('--jurisdictions ', 'comma-separated pack codes, e.g. us-delaware,nz,uk,hk') - .action((opts: { jurisdictions: string }) => { - console.log(kleur.cyan(`[stub] entity compare · ${opts.jurisdictions}`)); - }); - -// ---- name-check / plan / docs ---------------------------------------- - -entityCmd - .command('name-check ') - .description('Run the pack name search (or create a manual name-check task)') - .option('--jurisdiction ', 'override the entity jurisdiction') - .option('--name ', 'override the candidate name (defaults to entity.legalName)') - .action((slug: string, opts: { jurisdiction?: string; name?: string }) => { - console.log(kleur.cyan(`[stub] entity name-check ${slug}${opts.name ? ` "${opts.name}"` : ''}`)); - }); - -const planCmd = entityCmd - .command('plan') - .description('Formation plan — required inputs, manual steps, recommended filing mode') - .action(() => { planCmd.help(); }); - -planCmd - .command('generate ') - .description('Generate a formation plan from the pack') - .action((slug: string) => { - console.log(kleur.cyan(`[stub] entity plan generate ${slug}`)); - }); - -const docsCmd = entityCmd - .command('docs') - .description('Document bundle — certificate, bylaws/constitution, checklist, filing packet') - .action(() => { docsCmd.help(); }); - -docsCmd - .command('generate ') - .description('Generate the full document bundle into ./entities//') - .action((slug: string) => { - console.log(kleur.cyan(`[stub] entity docs generate ${slug}`)); - }); - -// ---- filing ---------------------------------------------------------- - -const filingCmd = entityCmd - .command('filing') - .description('Filing handoff — direct / assisted / packet-only / provider / stub') - .action(() => { filingCmd.help(); }); - -filingCmd - .command('handoff ') - .description('Hand off the filing in the selected mode') - .requiredOption('--mode ', 'direct | assisted | packet-only | provider | stub') - .action((slug: string, opts: { mode: string }) => { - console.log(kleur.green(`[stub] entity filing handoff ${slug} · mode=${opts.mode}`)); - }); - -// ---- compliance / status / audit ------------------------------------- - -const complianceCmd = entityCmd - .command('compliance') - .description('Recurring compliance tasks — annual returns, tax filings, reminders') - .action(() => { complianceCmd.help(); }); - -complianceCmd - .command('enable ') - .description('Generate the compliance calendar for the entity') - .action((slug: string) => { - console.log(kleur.green(`[stub] entity compliance enable ${slug}`)); - }); - -complianceCmd - .command('list ') - .description('Show open / overdue / upcoming compliance tasks') - .option('--status ', 'filter by status (open, blocked, submitted, complete, overdue)') - .action((slug: string, opts: { status?: string }) => { - console.log(kleur.dim(`[stub] entity compliance list ${slug}${opts.status ? ` · ${opts.status}` : ''}`)); - }); - -entityCmd - .command('status ') - .description('Show the entity lifecycle state (draft → planned → packet-ready → ... → active)') - .action((slug: string) => { - console.log(kleur.dim(`[stub] entity status ${slug}`)); - }); - -const auditCmd = entityCmd - .command('audit') - .description('Immutable audit log of entity actions (jsonl)') - .action(() => { auditCmd.help(); }); - -auditCmd - .command('tail ') - .description('Stream the audit log for the entity') - .option('-n ', 'number of lines to show', '20') - .action((slug: string, opts: { n: string }) => { - console.log(kleur.dim(`[stub] entity audit tail ${slug} -n ${opts.n}`)); - }); - -// ---- stub / experimental --------------------------------------------- - -const stubCmd = entityCmd - .command('stub') - .description('Stub pack operations — model an entity in an unsupported jurisdiction') - .action(() => { stubCmd.help(); }); - -stubCmd - .command('init ') - .description('Initialise a stub-pack workspace (e.g. india, south-africa, nigeria)') - .option('--entity-type ', 'override the default entity type for the stub') - .action((jurisdiction: string, opts: { entityType?: string }) => { - console.log(kleur.yellow(`[stub] entity stub init ${jurisdiction}${opts.entityType ? ` · ${opts.entityType}` : ''}`)); - }); - -const expCmd = entityCmd - .command('experimental') - .description('Experimental packs — behind a feature flag, narrow use cases only') - .action(() => { expCmd.help(); }); - -expCmd - .command('init ') - .description('Initialise an experimental workspace (e.g. dao-wy)') - .option('--type ', 'entity type (dao-llc for dao-wy)') - .action((pack: string, opts: { type?: string }) => { - console.log(kleur.magenta(`[stub] entity experimental init ${pack}${opts.type ? ` · ${opts.type}` : ''}`)); + .action(async (pack: string) => { + const code = pack.replace(/^entity-/, '').replace(/^@profullstack\/sh1pt-entity-/, ''); + try { + const m = await import(`@profullstack/sh1pt-entity-${code}`); + const d: JurisdictionDescribe = (m.default as any).describe(); + console.log(kleur.bold(`\n${d.displayName} (${d.jurisdictionCode})`)); + console.log(` pack id: ${kleur.cyan(d.packId)}`); + const lc = d.supportLevel === 'full' ? kleur.green : kleur.yellow; + console.log(` support: ${lc(d.supportLevel)}`); + console.log(` version: ${d.version}`); + console.log(` types: ${(d.entityTypesSupported ?? []).join(', ')}`); + console.log(` filing: ${(d.filingModesSupported ?? []).join(', ')}`); + if (d.requiredInputs?.length) console.log(` inputs: ${d.requiredInputs.join(', ')}`); + if (d.requiredManualSteps?.length) console.log(` manual: ${d.requiredManualSteps.join(', ')}`); + if (d.experimental) console.log(kleur.magenta(' ⚠ experimental')); + } catch { + console.error(kleur.red(`pack not found: ${code}`)); process.exit(1); + } });