@growthub/cli 0.3.42 → 0.3.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. package/README.md +91 -220
  2. package/assets/shared-templates/ad-formats/INDEX.md +94 -0
  3. package/assets/shared-templates/ad-formats/bedroom-minimic-talk.md +197 -0
  4. package/assets/shared-templates/ad-formats/frame-analysis.md +209 -0
  5. package/assets/shared-templates/ad-formats/process-specialist-medical.md +105 -0
  6. package/assets/shared-templates/ad-formats/villain-animation.md +183 -0
  7. package/assets/shared-templates/manifest.json +23 -0
  8. package/assets/shared-templates/scene-modules/INDEX.md +151 -0
  9. package/assets/shared-templates/scene-modules/body/before-after-flatlay.md +143 -0
  10. package/assets/shared-templates/scene-modules/body/minimic-problem.md +109 -0
  11. package/assets/shared-templates/scene-modules/body/product-demo-glow.md +123 -0
  12. package/assets/shared-templates/scene-modules/body/tiktok-skeptic-pivot.md +119 -0
  13. package/assets/shared-templates/scene-modules/body/villain-agitation.md +156 -0
  14. package/assets/shared-templates/scene-modules/cta/bogo-meme-bookend.md +144 -0
  15. package/assets/shared-templates/scene-modules/cta/guarantee-close.md +143 -0
  16. package/assets/shared-templates/scene-modules/hooks/dollar-amount.md +105 -0
  17. package/assets/shared-templates/scene-modules/hooks/meme-overlay.md +104 -0
  18. package/assets/shared-templates/scene-modules/hooks/pov-confession.md +92 -0
  19. package/assets/shared-templates/scene-modules/hooks/tiktok-comment.md +116 -0
  20. package/assets/shared-templates/scene-modules/hooks/villain-hook.md +134 -0
  21. package/dist/index.js +2609 -600
  22. package/package.json +1 -1
  23. package/dist/index.js.map +0 -7
package/dist/index.js CHANGED
@@ -10,15 +10,15 @@ var __export = (target, all) => {
10
10
  };
11
11
 
12
12
  // ../packages/shared/src/constants.ts
13
- var COMPANY_STATUSES, DEPLOYMENT_MODES, DEPLOYMENT_EXPOSURES, SURFACE_PROFILES, AUTH_BASE_URL_MODES, AGENT_STATUSES, AGENT_ADAPTER_TYPES, AGENT_ROLES, AGENT_ICON_NAMES, TICKET_STATUSES, ISSUE_STATUSES, ISSUE_PRIORITIES, GOAL_LEVELS, GOAL_STATUSES, PROJECT_STATUSES, APPROVAL_TYPES, SECRET_PROVIDERS, STORAGE_PROVIDERS, BILLING_TYPES, FINANCE_EVENT_KINDS, FINANCE_DIRECTIONS, FINANCE_UNITS, BUDGET_SCOPE_TYPES, BUDGET_METRICS, BUDGET_WINDOW_KINDS, BUDGET_INCIDENT_RESOLUTION_ACTIONS, INVITE_JOIN_TYPES, JOIN_REQUEST_TYPES, JOIN_REQUEST_STATUSES, PERMISSION_KEYS, PLUGIN_STATUSES, PLUGIN_CATEGORIES, PLUGIN_CAPABILITIES, PLUGIN_UI_SLOT_TYPES, PLUGIN_RESERVED_COMPANY_ROUTE_SEGMENTS, PLUGIN_LAUNCHER_PLACEMENT_ZONES, PLUGIN_LAUNCHER_ACTIONS, PLUGIN_LAUNCHER_BOUNDS, PLUGIN_LAUNCHER_RENDER_ENVIRONMENTS, PLUGIN_UI_SLOT_ENTITY_TYPES, PLUGIN_STATE_SCOPE_KINDS;
13
+ var COMPANY_STATUSES, DEPLOYMENT_MODES, DEPLOYMENT_EXPOSURES, AUTH_BASE_URL_MODES, SURFACE_PROFILES, AGENT_STATUSES, AGENT_ADAPTER_TYPES, AGENT_ROLES, AGENT_ICON_NAMES, TICKET_STAGE_KINDS, TICKET_STAGE_HANDOFF_MODES, TICKET_STATUSES, ISSUE_STATUSES, ISSUE_PRIORITIES, GOAL_LEVELS, GOAL_STATUSES, PROJECT_STATUSES, APPROVAL_TYPES, SECRET_PROVIDERS, STORAGE_PROVIDERS, BILLING_TYPES, FINANCE_EVENT_KINDS, FINANCE_DIRECTIONS, FINANCE_UNITS, BUDGET_SCOPE_TYPES, BUDGET_METRICS, BUDGET_WINDOW_KINDS, BUDGET_INCIDENT_RESOLUTION_ACTIONS, INVITE_JOIN_TYPES, JOIN_REQUEST_TYPES, JOIN_REQUEST_STATUSES, PERMISSION_KEYS, PLUGIN_STATUSES, PLUGIN_CATEGORIES, PLUGIN_CAPABILITIES, PLUGIN_UI_SLOT_TYPES, PLUGIN_RESERVED_COMPANY_ROUTE_SEGMENTS, PLUGIN_LAUNCHER_PLACEMENT_ZONES, PLUGIN_LAUNCHER_ACTIONS, PLUGIN_LAUNCHER_BOUNDS, PLUGIN_LAUNCHER_RENDER_ENVIRONMENTS, PLUGIN_UI_SLOT_ENTITY_TYPES, PLUGIN_STATE_SCOPE_KINDS;
14
14
  var init_constants = __esm({
15
15
  "../packages/shared/src/constants.ts"() {
16
16
  "use strict";
17
17
  COMPANY_STATUSES = ["active", "paused", "archived"];
18
18
  DEPLOYMENT_MODES = ["local_trusted", "authenticated"];
19
19
  DEPLOYMENT_EXPOSURES = ["private", "public"];
20
- SURFACE_PROFILES = ["dx", "gtm"];
21
20
  AUTH_BASE_URL_MODES = ["auto", "explicit"];
21
+ SURFACE_PROFILES = ["dx", "gtm"];
22
22
  AGENT_STATUSES = [
23
23
  "active",
24
24
  "paused",
@@ -95,9 +95,24 @@ var init_constants = __esm({
95
95
  "pentagon",
96
96
  "fingerprint"
97
97
  ];
98
+ TICKET_STAGE_KINDS = [
99
+ "planning",
100
+ "execution",
101
+ "review",
102
+ "qa",
103
+ "human",
104
+ "custom"
105
+ ];
106
+ TICKET_STAGE_HANDOFF_MODES = [
107
+ "seamless",
108
+ "context_only",
109
+ "manual"
110
+ ];
98
111
  TICKET_STATUSES = [
99
112
  "active",
100
113
  "paused",
114
+ "completed",
115
+ "archived",
101
116
  "done",
102
117
  "cancelled"
103
118
  ];
@@ -893,17 +908,63 @@ var init_execution_workspace = __esm({
893
908
  }
894
909
  });
895
910
 
911
+ // ../packages/shared/src/ticket-stages.ts
912
+ function normalizeTicketStageKey(value) {
913
+ return value.trim().toLowerCase().replace(/\s+/g, "_");
914
+ }
915
+ var init_ticket_stages = __esm({
916
+ "../packages/shared/src/ticket-stages.ts"() {
917
+ "use strict";
918
+ init_constants();
919
+ }
920
+ });
921
+
896
922
  // ../packages/shared/src/validators/ticket.ts
897
923
  import { z as z11 } from "zod";
898
- var createTicketSchema, updateTicketSchema, advanceTicketStageSchema;
924
+ var ticketStageDefinitionSchema, ticketStageDefinitionsSchema, createTicketSchema, updateTicketSchema, advanceTicketStageSchema;
899
925
  var init_ticket = __esm({
900
926
  "../packages/shared/src/validators/ticket.ts"() {
901
927
  "use strict";
902
928
  init_constants();
929
+ init_ticket_stages();
930
+ ticketStageDefinitionSchema = z11.object({
931
+ key: z11.string().min(1),
932
+ label: z11.string().min(1).max(120),
933
+ kind: z11.enum(TICKET_STAGE_KINDS).nullable().optional(),
934
+ ownerRole: z11.enum(AGENT_ROLES).nullable().optional(),
935
+ handoffMode: z11.enum(TICKET_STAGE_HANDOFF_MODES).nullable().optional(),
936
+ instructions: z11.string().nullable().optional(),
937
+ exitCriteria: z11.string().nullable().optional(),
938
+ metadata: z11.record(z11.unknown()).nullable().optional()
939
+ });
940
+ ticketStageDefinitionsSchema = z11.array(ticketStageDefinitionSchema).min(1).superRefine((value, ctx) => {
941
+ const seen = /* @__PURE__ */ new Set();
942
+ value.forEach((definition, index51) => {
943
+ const normalizedKey = normalizeTicketStageKey(String(definition.key));
944
+ if (!normalizedKey) {
945
+ ctx.addIssue({
946
+ code: z11.ZodIssueCode.custom,
947
+ path: [index51, "key"],
948
+ message: "Stage key must not be empty"
949
+ });
950
+ return;
951
+ }
952
+ if (seen.has(normalizedKey)) {
953
+ ctx.addIssue({
954
+ code: z11.ZodIssueCode.custom,
955
+ path: [index51, "key"],
956
+ message: "Stage keys must be unique"
957
+ });
958
+ return;
959
+ }
960
+ seen.add(normalizedKey);
961
+ });
962
+ });
903
963
  createTicketSchema = z11.object({
904
964
  title: z11.string().min(1).max(500),
905
965
  description: z11.string().optional(),
906
- stageOrder: z11.array(z11.string().min(1)).optional(),
966
+ stageOrder: z11.array(z11.string().min(1)).min(1).optional(),
967
+ stageDefinitions: ticketStageDefinitionsSchema.optional(),
907
968
  metadata: z11.record(z11.unknown()).optional(),
908
969
  instructions: z11.string().optional(),
909
970
  leadAgentId: z11.string().uuid().nullable().optional()
@@ -913,7 +974,8 @@ var init_ticket = __esm({
913
974
  description: z11.string().nullable().optional(),
914
975
  status: z11.enum(TICKET_STATUSES).optional(),
915
976
  currentStage: z11.string().min(1).optional(),
916
- stageOrder: z11.array(z11.string().min(1)).optional(),
977
+ stageOrder: z11.array(z11.string().min(1)).min(1).optional(),
978
+ stageDefinitions: ticketStageDefinitionsSchema.optional(),
917
979
  metadata: z11.record(z11.unknown()).optional(),
918
980
  instructions: z11.string().optional(),
919
981
  leadAgentId: z11.string().uuid().nullable().optional()
@@ -1619,11 +1681,11 @@ var init_config_schema = __esm({
1619
1681
  baseUrlMode: z19.enum(AUTH_BASE_URL_MODES).default("auto"),
1620
1682
  publicBaseUrl: z19.string().url().optional(),
1621
1683
  disableSignUp: z19.boolean().default(false),
1622
- token: z19.string().min(1).optional(),
1684
+ token: z19.string().optional(),
1623
1685
  growthubBaseUrl: z19.string().url().optional(),
1624
1686
  growthubPortalBaseUrl: z19.string().url().optional(),
1625
- growthubMachineLabel: z19.string().min(1).optional(),
1626
- growthubWorkspaceLabel: z19.string().min(1).optional()
1687
+ growthubMachineLabel: z19.string().optional(),
1688
+ growthubWorkspaceLabel: z19.string().optional()
1627
1689
  });
1628
1690
  surfaceConfigSchema = z19.object({
1629
1691
  profile: z19.enum(SURFACE_PROFILES).default("dx")
@@ -1768,6 +1830,13 @@ var init_surface_runtime = __esm({
1768
1830
  }
1769
1831
  });
1770
1832
 
1833
+ // ../packages/shared/src/agent-surface-metadata.ts
1834
+ var init_agent_surface_metadata = __esm({
1835
+ "../packages/shared/src/agent-surface-metadata.ts"() {
1836
+ "use strict";
1837
+ }
1838
+ });
1839
+
1771
1840
  // ../packages/shared/src/gtm.ts
1772
1841
  function humanizeToken(value) {
1773
1842
  return value.replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim().replace(/\b\w/g, (match) => match.toUpperCase());
@@ -1860,7 +1929,7 @@ function coerceGtmState(raw) {
1860
1929
  ...candidate.knowledge?.table?.metadata
1861
1930
  }
1862
1931
  },
1863
- items: Array.isArray(candidate.knowledge?.items) && candidate.knowledge.items.length > 0 ? candidate.knowledge.items.map((item, index50) => ({
1932
+ items: Array.isArray(candidate.knowledge?.items) && candidate.knowledge.items.length > 0 ? candidate.knowledge.items.map((item, index51) => ({
1864
1933
  ...fallbackItemTemplate,
1865
1934
  ...item,
1866
1935
  metadata: {
@@ -1869,7 +1938,7 @@ function coerceGtmState(raw) {
1869
1938
  }
1870
1939
  })) : fallback.knowledge.items
1871
1940
  },
1872
- connectors: Array.isArray(candidate.connectors) && candidate.connectors.length > 0 ? candidate.connectors.map((connector, index50) => ({
1941
+ connectors: Array.isArray(candidate.connectors) && candidate.connectors.length > 0 ? candidate.connectors.map((connector, index51) => ({
1873
1942
  ...fallbackConnectorTemplate,
1874
1943
  ...connector,
1875
1944
  config: {
@@ -1937,6 +2006,54 @@ var init_gtm = __esm({
1937
2006
  }
1938
2007
  });
1939
2008
 
2009
+ // ../packages/shared/src/growthub-query-engine.ts
2010
+ var init_growthub_query_engine = __esm({
2011
+ "../packages/shared/src/growthub-query-engine.ts"() {
2012
+ "use strict";
2013
+ }
2014
+ });
2015
+
2016
+ // ../packages/shared/src/kb-skill-bundle/types.ts
2017
+ var init_types = __esm({
2018
+ "../packages/shared/src/kb-skill-bundle/types.ts"() {
2019
+ "use strict";
2020
+ }
2021
+ });
2022
+
2023
+ // ../packages/shared/src/kb-skill-bundle/metadata.ts
2024
+ var init_metadata = __esm({
2025
+ "../packages/shared/src/kb-skill-bundle/metadata.ts"() {
2026
+ "use strict";
2027
+ }
2028
+ });
2029
+
2030
+ // ../packages/shared/src/kb-skill-bundle/bundle.ts
2031
+ var init_bundle = __esm({
2032
+ "../packages/shared/src/kb-skill-bundle/bundle.ts"() {
2033
+ "use strict";
2034
+ init_types();
2035
+ }
2036
+ });
2037
+
2038
+ // ../packages/shared/src/kb-skill-bundle/prompt.ts
2039
+ var init_prompt = __esm({
2040
+ "../packages/shared/src/kb-skill-bundle/prompt.ts"() {
2041
+ "use strict";
2042
+ init_bundle();
2043
+ }
2044
+ });
2045
+
2046
+ // ../packages/shared/src/kb-skill-bundle/index.ts
2047
+ var init_kb_skill_bundle = __esm({
2048
+ "../packages/shared/src/kb-skill-bundle/index.ts"() {
2049
+ "use strict";
2050
+ init_types();
2051
+ init_metadata();
2052
+ init_bundle();
2053
+ init_prompt();
2054
+ }
2055
+ });
2056
+
1940
2057
  // ../packages/shared/src/index.ts
1941
2058
  var init_src = __esm({
1942
2059
  "../packages/shared/src/index.ts"() {
@@ -1950,7 +2067,11 @@ var init_src = __esm({
1950
2067
  init_project_mentions();
1951
2068
  init_config_schema();
1952
2069
  init_surface_runtime();
2070
+ init_ticket_stages();
2071
+ init_agent_surface_metadata();
1953
2072
  init_gtm();
2073
+ init_growthub_query_engine();
2074
+ init_kb_skill_bundle();
1954
2075
  }
1955
2076
  });
1956
2077
 
@@ -4474,8 +4595,38 @@ var init_documents = __esm({
4474
4595
  }
4475
4596
  });
4476
4597
 
4598
+ // ../packages/db/src/schema/kb_skill_docs.ts
4599
+ import { pgTable as pgTable38, uuid as uuid37, text as text39, boolean as boolean8, timestamp as timestamp38, index as index34, jsonb as jsonb20 } from "drizzle-orm/pg-core";
4600
+ var kbSkillDocs;
4601
+ var init_kb_skill_docs = __esm({
4602
+ "../packages/db/src/schema/kb_skill_docs.ts"() {
4603
+ "use strict";
4604
+ init_companies();
4605
+ kbSkillDocs = pgTable38(
4606
+ "kb_skill_docs",
4607
+ {
4608
+ id: uuid37("id").primaryKey().defaultRandom(),
4609
+ companyId: uuid37("company_id").notNull().references(() => companies.id, { onDelete: "cascade" }),
4610
+ name: text39("name").notNull(),
4611
+ description: text39("description").notNull().default(""),
4612
+ body: text39("body").notNull().default(""),
4613
+ format: text39("format").notNull().default("markdown"),
4614
+ source: text39("source").notNull().default("custom"),
4615
+ metadata: jsonb20("metadata").$type().notNull().default({}),
4616
+ isActive: boolean8("is_active").notNull().default(true),
4617
+ createdAt: timestamp38("created_at", { withTimezone: true }).notNull().defaultNow(),
4618
+ updatedAt: timestamp38("updated_at", { withTimezone: true }).notNull().defaultNow()
4619
+ },
4620
+ (table) => ({
4621
+ companyActiveIdx: index34("kb_skill_docs_company_active_idx").on(table.companyId, table.isActive),
4622
+ companyUpdatedIdx: index34("kb_skill_docs_company_updated_idx").on(table.companyId, table.updatedAt)
4623
+ })
4624
+ );
4625
+ }
4626
+ });
4627
+
4477
4628
  // ../packages/db/src/schema/document_revisions.ts
4478
- import { pgTable as pgTable38, uuid as uuid37, text as text39, integer as integer12, timestamp as timestamp38, index as index34, uniqueIndex as uniqueIndex18 } from "drizzle-orm/pg-core";
4629
+ import { pgTable as pgTable39, uuid as uuid38, text as text40, integer as integer12, timestamp as timestamp39, index as index35, uniqueIndex as uniqueIndex18 } from "drizzle-orm/pg-core";
4479
4630
  var documentRevisions;
4480
4631
  var init_document_revisions = __esm({
4481
4632
  "../packages/db/src/schema/document_revisions.ts"() {
@@ -4483,25 +4634,25 @@ var init_document_revisions = __esm({
4483
4634
  init_companies();
4484
4635
  init_agents();
4485
4636
  init_documents();
4486
- documentRevisions = pgTable38(
4637
+ documentRevisions = pgTable39(
4487
4638
  "document_revisions",
4488
4639
  {
4489
- id: uuid37("id").primaryKey().defaultRandom(),
4490
- companyId: uuid37("company_id").notNull().references(() => companies.id),
4491
- documentId: uuid37("document_id").notNull().references(() => documents.id, { onDelete: "cascade" }),
4640
+ id: uuid38("id").primaryKey().defaultRandom(),
4641
+ companyId: uuid38("company_id").notNull().references(() => companies.id),
4642
+ documentId: uuid38("document_id").notNull().references(() => documents.id, { onDelete: "cascade" }),
4492
4643
  revisionNumber: integer12("revision_number").notNull(),
4493
- body: text39("body").notNull(),
4494
- changeSummary: text39("change_summary"),
4495
- createdByAgentId: uuid37("created_by_agent_id").references(() => agents.id, { onDelete: "set null" }),
4496
- createdByUserId: text39("created_by_user_id"),
4497
- createdAt: timestamp38("created_at", { withTimezone: true }).notNull().defaultNow()
4644
+ body: text40("body").notNull(),
4645
+ changeSummary: text40("change_summary"),
4646
+ createdByAgentId: uuid38("created_by_agent_id").references(() => agents.id, { onDelete: "set null" }),
4647
+ createdByUserId: text40("created_by_user_id"),
4648
+ createdAt: timestamp39("created_at", { withTimezone: true }).notNull().defaultNow()
4498
4649
  },
4499
4650
  (table) => ({
4500
4651
  documentRevisionUq: uniqueIndex18("document_revisions_document_revision_uq").on(
4501
4652
  table.documentId,
4502
4653
  table.revisionNumber
4503
4654
  ),
4504
- companyDocumentCreatedIdx: index34("document_revisions_company_document_created_idx").on(
4655
+ companyDocumentCreatedIdx: index35("document_revisions_company_document_created_idx").on(
4505
4656
  table.companyId,
4506
4657
  table.documentId,
4507
4658
  table.createdAt
@@ -4512,7 +4663,7 @@ var init_document_revisions = __esm({
4512
4663
  });
4513
4664
 
4514
4665
  // ../packages/db/src/schema/issue_documents.ts
4515
- import { pgTable as pgTable39, uuid as uuid38, text as text40, timestamp as timestamp39, index as index35, uniqueIndex as uniqueIndex19 } from "drizzle-orm/pg-core";
4666
+ import { pgTable as pgTable40, uuid as uuid39, text as text41, timestamp as timestamp40, index as index36, uniqueIndex as uniqueIndex19 } from "drizzle-orm/pg-core";
4516
4667
  var issueDocuments;
4517
4668
  var init_issue_documents = __esm({
4518
4669
  "../packages/db/src/schema/issue_documents.ts"() {
@@ -4520,16 +4671,16 @@ var init_issue_documents = __esm({
4520
4671
  init_companies();
4521
4672
  init_issues();
4522
4673
  init_documents();
4523
- issueDocuments = pgTable39(
4674
+ issueDocuments = pgTable40(
4524
4675
  "issue_documents",
4525
4676
  {
4526
- id: uuid38("id").primaryKey().defaultRandom(),
4527
- companyId: uuid38("company_id").notNull().references(() => companies.id),
4528
- issueId: uuid38("issue_id").notNull().references(() => issues.id, { onDelete: "cascade" }),
4529
- documentId: uuid38("document_id").notNull().references(() => documents.id, { onDelete: "cascade" }),
4530
- key: text40("key").notNull(),
4531
- createdAt: timestamp39("created_at", { withTimezone: true }).notNull().defaultNow(),
4532
- updatedAt: timestamp39("updated_at", { withTimezone: true }).notNull().defaultNow()
4677
+ id: uuid39("id").primaryKey().defaultRandom(),
4678
+ companyId: uuid39("company_id").notNull().references(() => companies.id),
4679
+ issueId: uuid39("issue_id").notNull().references(() => issues.id, { onDelete: "cascade" }),
4680
+ documentId: uuid39("document_id").notNull().references(() => documents.id, { onDelete: "cascade" }),
4681
+ key: text41("key").notNull(),
4682
+ createdAt: timestamp40("created_at", { withTimezone: true }).notNull().defaultNow(),
4683
+ updatedAt: timestamp40("updated_at", { withTimezone: true }).notNull().defaultNow()
4533
4684
  },
4534
4685
  (table) => ({
4535
4686
  companyIssueKeyUq: uniqueIndex19("issue_documents_company_issue_key_uq").on(
@@ -4538,7 +4689,7 @@ var init_issue_documents = __esm({
4538
4689
  table.key
4539
4690
  ),
4540
4691
  documentUq: uniqueIndex19("issue_documents_document_uq").on(table.documentId),
4541
- companyIssueUpdatedIdx: index35("issue_documents_company_issue_updated_idx").on(
4692
+ companyIssueUpdatedIdx: index36("issue_documents_company_issue_updated_idx").on(
4542
4693
  table.companyId,
4543
4694
  table.issueId,
4544
4695
  table.updatedAt
@@ -4549,7 +4700,7 @@ var init_issue_documents = __esm({
4549
4700
  });
4550
4701
 
4551
4702
  // ../packages/db/src/schema/heartbeat_run_events.ts
4552
- import { pgTable as pgTable40, uuid as uuid39, text as text41, timestamp as timestamp40, integer as integer13, jsonb as jsonb20, index as index36, bigserial } from "drizzle-orm/pg-core";
4703
+ import { pgTable as pgTable41, uuid as uuid40, text as text42, timestamp as timestamp41, integer as integer13, jsonb as jsonb21, index as index37, bigserial } from "drizzle-orm/pg-core";
4553
4704
  var heartbeatRunEvents;
4554
4705
  var init_heartbeat_run_events = __esm({
4555
4706
  "../packages/db/src/schema/heartbeat_run_events.ts"() {
@@ -4557,33 +4708,33 @@ var init_heartbeat_run_events = __esm({
4557
4708
  init_companies();
4558
4709
  init_agents();
4559
4710
  init_heartbeat_runs();
4560
- heartbeatRunEvents = pgTable40(
4711
+ heartbeatRunEvents = pgTable41(
4561
4712
  "heartbeat_run_events",
4562
4713
  {
4563
4714
  id: bigserial("id", { mode: "number" }).primaryKey(),
4564
- companyId: uuid39("company_id").notNull().references(() => companies.id),
4565
- runId: uuid39("run_id").notNull().references(() => heartbeatRuns.id),
4566
- agentId: uuid39("agent_id").notNull().references(() => agents.id),
4715
+ companyId: uuid40("company_id").notNull().references(() => companies.id),
4716
+ runId: uuid40("run_id").notNull().references(() => heartbeatRuns.id),
4717
+ agentId: uuid40("agent_id").notNull().references(() => agents.id),
4567
4718
  seq: integer13("seq").notNull(),
4568
- eventType: text41("event_type").notNull(),
4569
- stream: text41("stream"),
4570
- level: text41("level"),
4571
- color: text41("color"),
4572
- message: text41("message"),
4573
- payload: jsonb20("payload").$type(),
4574
- createdAt: timestamp40("created_at", { withTimezone: true }).notNull().defaultNow()
4719
+ eventType: text42("event_type").notNull(),
4720
+ stream: text42("stream"),
4721
+ level: text42("level"),
4722
+ color: text42("color"),
4723
+ message: text42("message"),
4724
+ payload: jsonb21("payload").$type(),
4725
+ createdAt: timestamp41("created_at", { withTimezone: true }).notNull().defaultNow()
4575
4726
  },
4576
4727
  (table) => ({
4577
- runSeqIdx: index36("heartbeat_run_events_run_seq_idx").on(table.runId, table.seq),
4578
- companyRunIdx: index36("heartbeat_run_events_company_run_idx").on(table.companyId, table.runId),
4579
- companyCreatedIdx: index36("heartbeat_run_events_company_created_idx").on(table.companyId, table.createdAt)
4728
+ runSeqIdx: index37("heartbeat_run_events_run_seq_idx").on(table.runId, table.seq),
4729
+ companyRunIdx: index37("heartbeat_run_events_company_run_idx").on(table.companyId, table.runId),
4730
+ companyCreatedIdx: index37("heartbeat_run_events_company_created_idx").on(table.companyId, table.createdAt)
4580
4731
  })
4581
4732
  );
4582
4733
  }
4583
4734
  });
4584
4735
 
4585
4736
  // ../packages/db/src/schema/cost_events.ts
4586
- import { pgTable as pgTable41, uuid as uuid40, text as text42, timestamp as timestamp41, integer as integer14, index as index37 } from "drizzle-orm/pg-core";
4737
+ import { pgTable as pgTable42, uuid as uuid41, text as text43, timestamp as timestamp42, integer as integer14, index as index38 } from "drizzle-orm/pg-core";
4587
4738
  var costEvents;
4588
4739
  var init_cost_events = __esm({
4589
4740
  "../packages/db/src/schema/cost_events.ts"() {
@@ -4594,46 +4745,46 @@ var init_cost_events = __esm({
4594
4745
  init_projects();
4595
4746
  init_goals();
4596
4747
  init_heartbeat_runs();
4597
- costEvents = pgTable41(
4748
+ costEvents = pgTable42(
4598
4749
  "cost_events",
4599
4750
  {
4600
- id: uuid40("id").primaryKey().defaultRandom(),
4601
- companyId: uuid40("company_id").notNull().references(() => companies.id),
4602
- agentId: uuid40("agent_id").notNull().references(() => agents.id),
4603
- issueId: uuid40("issue_id").references(() => issues.id),
4604
- projectId: uuid40("project_id").references(() => projects.id),
4605
- goalId: uuid40("goal_id").references(() => goals.id),
4606
- heartbeatRunId: uuid40("heartbeat_run_id").references(() => heartbeatRuns.id),
4607
- billingCode: text42("billing_code"),
4608
- provider: text42("provider").notNull(),
4609
- biller: text42("biller").notNull().default("unknown"),
4610
- billingType: text42("billing_type").notNull().default("unknown"),
4611
- model: text42("model").notNull(),
4751
+ id: uuid41("id").primaryKey().defaultRandom(),
4752
+ companyId: uuid41("company_id").notNull().references(() => companies.id),
4753
+ agentId: uuid41("agent_id").notNull().references(() => agents.id),
4754
+ issueId: uuid41("issue_id").references(() => issues.id),
4755
+ projectId: uuid41("project_id").references(() => projects.id),
4756
+ goalId: uuid41("goal_id").references(() => goals.id),
4757
+ heartbeatRunId: uuid41("heartbeat_run_id").references(() => heartbeatRuns.id),
4758
+ billingCode: text43("billing_code"),
4759
+ provider: text43("provider").notNull(),
4760
+ biller: text43("biller").notNull().default("unknown"),
4761
+ billingType: text43("billing_type").notNull().default("unknown"),
4762
+ model: text43("model").notNull(),
4612
4763
  inputTokens: integer14("input_tokens").notNull().default(0),
4613
4764
  cachedInputTokens: integer14("cached_input_tokens").notNull().default(0),
4614
4765
  outputTokens: integer14("output_tokens").notNull().default(0),
4615
4766
  costCents: integer14("cost_cents").notNull(),
4616
- occurredAt: timestamp41("occurred_at", { withTimezone: true }).notNull(),
4617
- createdAt: timestamp41("created_at", { withTimezone: true }).notNull().defaultNow()
4767
+ occurredAt: timestamp42("occurred_at", { withTimezone: true }).notNull(),
4768
+ createdAt: timestamp42("created_at", { withTimezone: true }).notNull().defaultNow()
4618
4769
  },
4619
4770
  (table) => ({
4620
- companyOccurredIdx: index37("cost_events_company_occurred_idx").on(table.companyId, table.occurredAt),
4621
- companyAgentOccurredIdx: index37("cost_events_company_agent_occurred_idx").on(
4771
+ companyOccurredIdx: index38("cost_events_company_occurred_idx").on(table.companyId, table.occurredAt),
4772
+ companyAgentOccurredIdx: index38("cost_events_company_agent_occurred_idx").on(
4622
4773
  table.companyId,
4623
4774
  table.agentId,
4624
4775
  table.occurredAt
4625
4776
  ),
4626
- companyProviderOccurredIdx: index37("cost_events_company_provider_occurred_idx").on(
4777
+ companyProviderOccurredIdx: index38("cost_events_company_provider_occurred_idx").on(
4627
4778
  table.companyId,
4628
4779
  table.provider,
4629
4780
  table.occurredAt
4630
4781
  ),
4631
- companyBillerOccurredIdx: index37("cost_events_company_biller_occurred_idx").on(
4782
+ companyBillerOccurredIdx: index38("cost_events_company_biller_occurred_idx").on(
4632
4783
  table.companyId,
4633
4784
  table.biller,
4634
4785
  table.occurredAt
4635
4786
  ),
4636
- companyHeartbeatRunIdx: index37("cost_events_company_heartbeat_run_idx").on(
4787
+ companyHeartbeatRunIdx: index38("cost_events_company_heartbeat_run_idx").on(
4637
4788
  table.companyId,
4638
4789
  table.heartbeatRunId
4639
4790
  )
@@ -4643,7 +4794,7 @@ var init_cost_events = __esm({
4643
4794
  });
4644
4795
 
4645
4796
  // ../packages/db/src/schema/finance_events.ts
4646
- import { pgTable as pgTable42, uuid as uuid41, text as text43, timestamp as timestamp42, integer as integer15, index as index38, boolean as boolean8, jsonb as jsonb21 } from "drizzle-orm/pg-core";
4797
+ import { pgTable as pgTable43, uuid as uuid42, text as text44, timestamp as timestamp43, integer as integer15, index as index39, boolean as boolean9, jsonb as jsonb22 } from "drizzle-orm/pg-core";
4647
4798
  var financeEvents;
4648
4799
  var init_finance_events = __esm({
4649
4800
  "../packages/db/src/schema/finance_events.ts"() {
@@ -4655,59 +4806,59 @@ var init_finance_events = __esm({
4655
4806
  init_goals();
4656
4807
  init_heartbeat_runs();
4657
4808
  init_cost_events();
4658
- financeEvents = pgTable42(
4809
+ financeEvents = pgTable43(
4659
4810
  "finance_events",
4660
4811
  {
4661
- id: uuid41("id").primaryKey().defaultRandom(),
4662
- companyId: uuid41("company_id").notNull().references(() => companies.id),
4663
- agentId: uuid41("agent_id").references(() => agents.id),
4664
- issueId: uuid41("issue_id").references(() => issues.id),
4665
- projectId: uuid41("project_id").references(() => projects.id),
4666
- goalId: uuid41("goal_id").references(() => goals.id),
4667
- heartbeatRunId: uuid41("heartbeat_run_id").references(() => heartbeatRuns.id),
4668
- costEventId: uuid41("cost_event_id").references(() => costEvents.id),
4669
- billingCode: text43("billing_code"),
4670
- description: text43("description"),
4671
- eventKind: text43("event_kind").notNull(),
4672
- direction: text43("direction").notNull().default("debit"),
4673
- biller: text43("biller").notNull(),
4674
- provider: text43("provider"),
4675
- executionAdapterType: text43("execution_adapter_type"),
4676
- pricingTier: text43("pricing_tier"),
4677
- region: text43("region"),
4678
- model: text43("model"),
4812
+ id: uuid42("id").primaryKey().defaultRandom(),
4813
+ companyId: uuid42("company_id").notNull().references(() => companies.id),
4814
+ agentId: uuid42("agent_id").references(() => agents.id),
4815
+ issueId: uuid42("issue_id").references(() => issues.id),
4816
+ projectId: uuid42("project_id").references(() => projects.id),
4817
+ goalId: uuid42("goal_id").references(() => goals.id),
4818
+ heartbeatRunId: uuid42("heartbeat_run_id").references(() => heartbeatRuns.id),
4819
+ costEventId: uuid42("cost_event_id").references(() => costEvents.id),
4820
+ billingCode: text44("billing_code"),
4821
+ description: text44("description"),
4822
+ eventKind: text44("event_kind").notNull(),
4823
+ direction: text44("direction").notNull().default("debit"),
4824
+ biller: text44("biller").notNull(),
4825
+ provider: text44("provider"),
4826
+ executionAdapterType: text44("execution_adapter_type"),
4827
+ pricingTier: text44("pricing_tier"),
4828
+ region: text44("region"),
4829
+ model: text44("model"),
4679
4830
  quantity: integer15("quantity"),
4680
- unit: text43("unit"),
4831
+ unit: text44("unit"),
4681
4832
  amountCents: integer15("amount_cents").notNull(),
4682
- currency: text43("currency").notNull().default("USD"),
4683
- estimated: boolean8("estimated").notNull().default(false),
4684
- externalInvoiceId: text43("external_invoice_id"),
4685
- metadataJson: jsonb21("metadata_json").$type(),
4686
- occurredAt: timestamp42("occurred_at", { withTimezone: true }).notNull(),
4687
- createdAt: timestamp42("created_at", { withTimezone: true }).notNull().defaultNow()
4833
+ currency: text44("currency").notNull().default("USD"),
4834
+ estimated: boolean9("estimated").notNull().default(false),
4835
+ externalInvoiceId: text44("external_invoice_id"),
4836
+ metadataJson: jsonb22("metadata_json").$type(),
4837
+ occurredAt: timestamp43("occurred_at", { withTimezone: true }).notNull(),
4838
+ createdAt: timestamp43("created_at", { withTimezone: true }).notNull().defaultNow()
4688
4839
  },
4689
4840
  (table) => ({
4690
- companyOccurredIdx: index38("finance_events_company_occurred_idx").on(table.companyId, table.occurredAt),
4691
- companyBillerOccurredIdx: index38("finance_events_company_biller_occurred_idx").on(
4841
+ companyOccurredIdx: index39("finance_events_company_occurred_idx").on(table.companyId, table.occurredAt),
4842
+ companyBillerOccurredIdx: index39("finance_events_company_biller_occurred_idx").on(
4692
4843
  table.companyId,
4693
4844
  table.biller,
4694
4845
  table.occurredAt
4695
4846
  ),
4696
- companyKindOccurredIdx: index38("finance_events_company_kind_occurred_idx").on(
4847
+ companyKindOccurredIdx: index39("finance_events_company_kind_occurred_idx").on(
4697
4848
  table.companyId,
4698
4849
  table.eventKind,
4699
4850
  table.occurredAt
4700
4851
  ),
4701
- companyDirectionOccurredIdx: index38("finance_events_company_direction_occurred_idx").on(
4852
+ companyDirectionOccurredIdx: index39("finance_events_company_direction_occurred_idx").on(
4702
4853
  table.companyId,
4703
4854
  table.direction,
4704
4855
  table.occurredAt
4705
4856
  ),
4706
- companyHeartbeatRunIdx: index38("finance_events_company_heartbeat_run_idx").on(
4857
+ companyHeartbeatRunIdx: index39("finance_events_company_heartbeat_run_idx").on(
4707
4858
  table.companyId,
4708
4859
  table.heartbeatRunId
4709
4860
  ),
4710
- companyCostEventIdx: index38("finance_events_company_cost_event_idx").on(
4861
+ companyCostEventIdx: index39("finance_events_company_cost_event_idx").on(
4711
4862
  table.companyId,
4712
4863
  table.costEventId
4713
4864
  )
@@ -4717,7 +4868,7 @@ var init_finance_events = __esm({
4717
4868
  });
4718
4869
 
4719
4870
  // ../packages/db/src/schema/approval_comments.ts
4720
- import { pgTable as pgTable43, uuid as uuid42, text as text44, timestamp as timestamp43, index as index39 } from "drizzle-orm/pg-core";
4871
+ import { pgTable as pgTable44, uuid as uuid43, text as text45, timestamp as timestamp44, index as index40 } from "drizzle-orm/pg-core";
4721
4872
  var approvalComments;
4722
4873
  var init_approval_comments = __esm({
4723
4874
  "../packages/db/src/schema/approval_comments.ts"() {
@@ -4725,22 +4876,22 @@ var init_approval_comments = __esm({
4725
4876
  init_companies();
4726
4877
  init_approvals();
4727
4878
  init_agents();
4728
- approvalComments = pgTable43(
4879
+ approvalComments = pgTable44(
4729
4880
  "approval_comments",
4730
4881
  {
4731
- id: uuid42("id").primaryKey().defaultRandom(),
4732
- companyId: uuid42("company_id").notNull().references(() => companies.id),
4733
- approvalId: uuid42("approval_id").notNull().references(() => approvals.id),
4734
- authorAgentId: uuid42("author_agent_id").references(() => agents.id),
4735
- authorUserId: text44("author_user_id"),
4736
- body: text44("body").notNull(),
4737
- createdAt: timestamp43("created_at", { withTimezone: true }).notNull().defaultNow(),
4738
- updatedAt: timestamp43("updated_at", { withTimezone: true }).notNull().defaultNow()
4882
+ id: uuid43("id").primaryKey().defaultRandom(),
4883
+ companyId: uuid43("company_id").notNull().references(() => companies.id),
4884
+ approvalId: uuid43("approval_id").notNull().references(() => approvals.id),
4885
+ authorAgentId: uuid43("author_agent_id").references(() => agents.id),
4886
+ authorUserId: text45("author_user_id"),
4887
+ body: text45("body").notNull(),
4888
+ createdAt: timestamp44("created_at", { withTimezone: true }).notNull().defaultNow(),
4889
+ updatedAt: timestamp44("updated_at", { withTimezone: true }).notNull().defaultNow()
4739
4890
  },
4740
4891
  (table) => ({
4741
- companyIdx: index39("approval_comments_company_idx").on(table.companyId),
4742
- approvalIdx: index39("approval_comments_approval_idx").on(table.approvalId),
4743
- approvalCreatedIdx: index39("approval_comments_approval_created_idx").on(
4892
+ companyIdx: index40("approval_comments_company_idx").on(table.companyId),
4893
+ approvalIdx: index40("approval_comments_approval_idx").on(table.approvalId),
4894
+ approvalCreatedIdx: index40("approval_comments_approval_created_idx").on(
4744
4895
  table.approvalId,
4745
4896
  table.createdAt
4746
4897
  )
@@ -4750,7 +4901,7 @@ var init_approval_comments = __esm({
4750
4901
  });
4751
4902
 
4752
4903
  // ../packages/db/src/schema/activity_log.ts
4753
- import { pgTable as pgTable44, uuid as uuid43, text as text45, timestamp as timestamp44, jsonb as jsonb22, index as index40 } from "drizzle-orm/pg-core";
4904
+ import { pgTable as pgTable45, uuid as uuid44, text as text46, timestamp as timestamp45, jsonb as jsonb23, index as index41 } from "drizzle-orm/pg-core";
4754
4905
  var activityLog;
4755
4906
  var init_activity_log = __esm({
4756
4907
  "../packages/db/src/schema/activity_log.ts"() {
@@ -4758,56 +4909,56 @@ var init_activity_log = __esm({
4758
4909
  init_companies();
4759
4910
  init_agents();
4760
4911
  init_heartbeat_runs();
4761
- activityLog = pgTable44(
4912
+ activityLog = pgTable45(
4762
4913
  "activity_log",
4763
4914
  {
4764
- id: uuid43("id").primaryKey().defaultRandom(),
4765
- companyId: uuid43("company_id").notNull().references(() => companies.id),
4766
- actorType: text45("actor_type").notNull().default("system"),
4767
- actorId: text45("actor_id").notNull(),
4768
- action: text45("action").notNull(),
4769
- entityType: text45("entity_type").notNull(),
4770
- entityId: text45("entity_id").notNull(),
4771
- agentId: uuid43("agent_id").references(() => agents.id),
4772
- runId: uuid43("run_id").references(() => heartbeatRuns.id),
4773
- details: jsonb22("details").$type(),
4774
- createdAt: timestamp44("created_at", { withTimezone: true }).notNull().defaultNow()
4915
+ id: uuid44("id").primaryKey().defaultRandom(),
4916
+ companyId: uuid44("company_id").notNull().references(() => companies.id),
4917
+ actorType: text46("actor_type").notNull().default("system"),
4918
+ actorId: text46("actor_id").notNull(),
4919
+ action: text46("action").notNull(),
4920
+ entityType: text46("entity_type").notNull(),
4921
+ entityId: text46("entity_id").notNull(),
4922
+ agentId: uuid44("agent_id").references(() => agents.id),
4923
+ runId: uuid44("run_id").references(() => heartbeatRuns.id),
4924
+ details: jsonb23("details").$type(),
4925
+ createdAt: timestamp45("created_at", { withTimezone: true }).notNull().defaultNow()
4775
4926
  },
4776
4927
  (table) => ({
4777
- companyCreatedIdx: index40("activity_log_company_created_idx").on(table.companyId, table.createdAt),
4778
- runIdIdx: index40("activity_log_run_id_idx").on(table.runId),
4779
- entityIdx: index40("activity_log_entity_type_id_idx").on(table.entityType, table.entityId)
4928
+ companyCreatedIdx: index41("activity_log_company_created_idx").on(table.companyId, table.createdAt),
4929
+ runIdIdx: index41("activity_log_run_id_idx").on(table.runId),
4930
+ entityIdx: index41("activity_log_entity_type_id_idx").on(table.entityType, table.entityId)
4780
4931
  })
4781
4932
  );
4782
4933
  }
4783
4934
  });
4784
4935
 
4785
4936
  // ../packages/db/src/schema/company_secrets.ts
4786
- import { pgTable as pgTable45, uuid as uuid44, text as text46, timestamp as timestamp45, integer as integer16, index as index41, uniqueIndex as uniqueIndex20 } from "drizzle-orm/pg-core";
4937
+ import { pgTable as pgTable46, uuid as uuid45, text as text47, timestamp as timestamp46, integer as integer16, index as index42, uniqueIndex as uniqueIndex20 } from "drizzle-orm/pg-core";
4787
4938
  var companySecrets;
4788
4939
  var init_company_secrets = __esm({
4789
4940
  "../packages/db/src/schema/company_secrets.ts"() {
4790
4941
  "use strict";
4791
4942
  init_companies();
4792
4943
  init_agents();
4793
- companySecrets = pgTable45(
4944
+ companySecrets = pgTable46(
4794
4945
  "company_secrets",
4795
4946
  {
4796
- id: uuid44("id").primaryKey().defaultRandom(),
4797
- companyId: uuid44("company_id").notNull().references(() => companies.id),
4798
- name: text46("name").notNull(),
4799
- provider: text46("provider").notNull().default("local_encrypted"),
4800
- externalRef: text46("external_ref"),
4947
+ id: uuid45("id").primaryKey().defaultRandom(),
4948
+ companyId: uuid45("company_id").notNull().references(() => companies.id),
4949
+ name: text47("name").notNull(),
4950
+ provider: text47("provider").notNull().default("local_encrypted"),
4951
+ externalRef: text47("external_ref"),
4801
4952
  latestVersion: integer16("latest_version").notNull().default(1),
4802
- description: text46("description"),
4803
- createdByAgentId: uuid44("created_by_agent_id").references(() => agents.id, { onDelete: "set null" }),
4804
- createdByUserId: text46("created_by_user_id"),
4805
- createdAt: timestamp45("created_at", { withTimezone: true }).notNull().defaultNow(),
4806
- updatedAt: timestamp45("updated_at", { withTimezone: true }).notNull().defaultNow()
4953
+ description: text47("description"),
4954
+ createdByAgentId: uuid45("created_by_agent_id").references(() => agents.id, { onDelete: "set null" }),
4955
+ createdByUserId: text47("created_by_user_id"),
4956
+ createdAt: timestamp46("created_at", { withTimezone: true }).notNull().defaultNow(),
4957
+ updatedAt: timestamp46("updated_at", { withTimezone: true }).notNull().defaultNow()
4807
4958
  },
4808
4959
  (table) => ({
4809
- companyIdx: index41("company_secrets_company_idx").on(table.companyId),
4810
- companyProviderIdx: index41("company_secrets_company_provider_idx").on(table.companyId, table.provider),
4960
+ companyIdx: index42("company_secrets_company_idx").on(table.companyId),
4961
+ companyProviderIdx: index42("company_secrets_company_provider_idx").on(table.companyId, table.provider),
4811
4962
  companyNameUq: uniqueIndex20("company_secrets_company_name_uq").on(table.companyId, table.name)
4812
4963
  })
4813
4964
  );
@@ -4815,29 +4966,29 @@ var init_company_secrets = __esm({
4815
4966
  });
4816
4967
 
4817
4968
  // ../packages/db/src/schema/company_secret_versions.ts
4818
- import { pgTable as pgTable46, uuid as uuid45, text as text47, timestamp as timestamp46, integer as integer17, jsonb as jsonb23, index as index42, uniqueIndex as uniqueIndex21 } from "drizzle-orm/pg-core";
4969
+ import { pgTable as pgTable47, uuid as uuid46, text as text48, timestamp as timestamp47, integer as integer17, jsonb as jsonb24, index as index43, uniqueIndex as uniqueIndex21 } from "drizzle-orm/pg-core";
4819
4970
  var companySecretVersions;
4820
4971
  var init_company_secret_versions = __esm({
4821
4972
  "../packages/db/src/schema/company_secret_versions.ts"() {
4822
4973
  "use strict";
4823
4974
  init_agents();
4824
4975
  init_company_secrets();
4825
- companySecretVersions = pgTable46(
4976
+ companySecretVersions = pgTable47(
4826
4977
  "company_secret_versions",
4827
4978
  {
4828
- id: uuid45("id").primaryKey().defaultRandom(),
4829
- secretId: uuid45("secret_id").notNull().references(() => companySecrets.id, { onDelete: "cascade" }),
4979
+ id: uuid46("id").primaryKey().defaultRandom(),
4980
+ secretId: uuid46("secret_id").notNull().references(() => companySecrets.id, { onDelete: "cascade" }),
4830
4981
  version: integer17("version").notNull(),
4831
- material: jsonb23("material").$type().notNull(),
4832
- valueSha256: text47("value_sha256").notNull(),
4833
- createdByAgentId: uuid45("created_by_agent_id").references(() => agents.id, { onDelete: "set null" }),
4834
- createdByUserId: text47("created_by_user_id"),
4835
- createdAt: timestamp46("created_at", { withTimezone: true }).notNull().defaultNow(),
4836
- revokedAt: timestamp46("revoked_at", { withTimezone: true })
4982
+ material: jsonb24("material").$type().notNull(),
4983
+ valueSha256: text48("value_sha256").notNull(),
4984
+ createdByAgentId: uuid46("created_by_agent_id").references(() => agents.id, { onDelete: "set null" }),
4985
+ createdByUserId: text48("created_by_user_id"),
4986
+ createdAt: timestamp47("created_at", { withTimezone: true }).notNull().defaultNow(),
4987
+ revokedAt: timestamp47("revoked_at", { withTimezone: true })
4837
4988
  },
4838
4989
  (table) => ({
4839
- secretIdx: index42("company_secret_versions_secret_idx").on(table.secretId, table.createdAt),
4840
- valueHashIdx: index42("company_secret_versions_value_sha256_idx").on(table.valueSha256),
4990
+ secretIdx: index43("company_secret_versions_secret_idx").on(table.secretId, table.createdAt),
4991
+ valueHashIdx: index43("company_secret_versions_value_sha256_idx").on(table.valueSha256),
4841
4992
  secretVersionUq: uniqueIndex21("company_secret_versions_secret_version_uq").on(table.secretId, table.version)
4842
4993
  })
4843
4994
  );
@@ -4846,61 +4997,61 @@ var init_company_secret_versions = __esm({
4846
4997
 
4847
4998
  // ../packages/db/src/schema/plugins.ts
4848
4999
  import {
4849
- pgTable as pgTable47,
4850
- uuid as uuid46,
4851
- text as text48,
5000
+ pgTable as pgTable48,
5001
+ uuid as uuid47,
5002
+ text as text49,
4852
5003
  integer as integer18,
4853
- timestamp as timestamp47,
4854
- jsonb as jsonb24,
4855
- index as index43,
5004
+ timestamp as timestamp48,
5005
+ jsonb as jsonb25,
5006
+ index as index44,
4856
5007
  uniqueIndex as uniqueIndex22
4857
5008
  } from "drizzle-orm/pg-core";
4858
5009
  var plugins;
4859
5010
  var init_plugins = __esm({
4860
5011
  "../packages/db/src/schema/plugins.ts"() {
4861
5012
  "use strict";
4862
- plugins = pgTable47(
5013
+ plugins = pgTable48(
4863
5014
  "plugins",
4864
5015
  {
4865
- id: uuid46("id").primaryKey().defaultRandom(),
4866
- pluginKey: text48("plugin_key").notNull(),
4867
- packageName: text48("package_name").notNull(),
4868
- version: text48("version").notNull(),
5016
+ id: uuid47("id").primaryKey().defaultRandom(),
5017
+ pluginKey: text49("plugin_key").notNull(),
5018
+ packageName: text49("package_name").notNull(),
5019
+ version: text49("version").notNull(),
4869
5020
  apiVersion: integer18("api_version").notNull().default(1),
4870
- categories: jsonb24("categories").$type().notNull().default([]),
4871
- manifestJson: jsonb24("manifest_json").$type().notNull(),
4872
- status: text48("status").$type().notNull().default("installed"),
5021
+ categories: jsonb25("categories").$type().notNull().default([]),
5022
+ manifestJson: jsonb25("manifest_json").$type().notNull(),
5023
+ status: text49("status").$type().notNull().default("installed"),
4873
5024
  installOrder: integer18("install_order"),
4874
5025
  /** Resolved package path for local-path installs; used to find worker entrypoint. */
4875
- packagePath: text48("package_path"),
4876
- lastError: text48("last_error"),
4877
- installedAt: timestamp47("installed_at", { withTimezone: true }).notNull().defaultNow(),
4878
- updatedAt: timestamp47("updated_at", { withTimezone: true }).notNull().defaultNow()
5026
+ packagePath: text49("package_path"),
5027
+ lastError: text49("last_error"),
5028
+ installedAt: timestamp48("installed_at", { withTimezone: true }).notNull().defaultNow(),
5029
+ updatedAt: timestamp48("updated_at", { withTimezone: true }).notNull().defaultNow()
4879
5030
  },
4880
5031
  (table) => ({
4881
5032
  pluginKeyIdx: uniqueIndex22("plugins_plugin_key_idx").on(table.pluginKey),
4882
- statusIdx: index43("plugins_status_idx").on(table.status)
5033
+ statusIdx: index44("plugins_status_idx").on(table.status)
4883
5034
  })
4884
5035
  );
4885
5036
  }
4886
5037
  });
4887
5038
 
4888
5039
  // ../packages/db/src/schema/plugin_config.ts
4889
- import { pgTable as pgTable48, uuid as uuid47, text as text49, timestamp as timestamp48, jsonb as jsonb25, uniqueIndex as uniqueIndex23 } from "drizzle-orm/pg-core";
5040
+ import { pgTable as pgTable49, uuid as uuid48, text as text50, timestamp as timestamp49, jsonb as jsonb26, uniqueIndex as uniqueIndex23 } from "drizzle-orm/pg-core";
4890
5041
  var pluginConfig;
4891
5042
  var init_plugin_config = __esm({
4892
5043
  "../packages/db/src/schema/plugin_config.ts"() {
4893
5044
  "use strict";
4894
5045
  init_plugins();
4895
- pluginConfig = pgTable48(
5046
+ pluginConfig = pgTable49(
4896
5047
  "plugin_config",
4897
5048
  {
4898
- id: uuid47("id").primaryKey().defaultRandom(),
4899
- pluginId: uuid47("plugin_id").notNull().references(() => plugins.id, { onDelete: "cascade" }),
4900
- configJson: jsonb25("config_json").$type().notNull().default({}),
4901
- lastError: text49("last_error"),
4902
- createdAt: timestamp48("created_at", { withTimezone: true }).notNull().defaultNow(),
4903
- updatedAt: timestamp48("updated_at", { withTimezone: true }).notNull().defaultNow()
5049
+ id: uuid48("id").primaryKey().defaultRandom(),
5050
+ pluginId: uuid48("plugin_id").notNull().references(() => plugins.id, { onDelete: "cascade" }),
5051
+ configJson: jsonb26("config_json").$type().notNull().default({}),
5052
+ lastError: text50("last_error"),
5053
+ createdAt: timestamp49("created_at", { withTimezone: true }).notNull().defaultNow(),
5054
+ updatedAt: timestamp49("updated_at", { withTimezone: true }).notNull().defaultNow()
4904
5055
  },
4905
5056
  (table) => ({
4906
5057
  pluginIdIdx: uniqueIndex23("plugin_config_plugin_id_idx").on(table.pluginId)
@@ -4910,28 +5061,28 @@ var init_plugin_config = __esm({
4910
5061
  });
4911
5062
 
4912
5063
  // ../packages/db/src/schema/plugin_company_settings.ts
4913
- import { pgTable as pgTable49, uuid as uuid48, text as text50, timestamp as timestamp49, jsonb as jsonb26, index as index44, uniqueIndex as uniqueIndex24, boolean as boolean9 } from "drizzle-orm/pg-core";
5064
+ import { pgTable as pgTable50, uuid as uuid49, text as text51, timestamp as timestamp50, jsonb as jsonb27, index as index45, uniqueIndex as uniqueIndex24, boolean as boolean10 } from "drizzle-orm/pg-core";
4914
5065
  var pluginCompanySettings;
4915
5066
  var init_plugin_company_settings = __esm({
4916
5067
  "../packages/db/src/schema/plugin_company_settings.ts"() {
4917
5068
  "use strict";
4918
5069
  init_companies();
4919
5070
  init_plugins();
4920
- pluginCompanySettings = pgTable49(
5071
+ pluginCompanySettings = pgTable50(
4921
5072
  "plugin_company_settings",
4922
5073
  {
4923
- id: uuid48("id").primaryKey().defaultRandom(),
4924
- companyId: uuid48("company_id").notNull().references(() => companies.id, { onDelete: "cascade" }),
4925
- pluginId: uuid48("plugin_id").notNull().references(() => plugins.id, { onDelete: "cascade" }),
4926
- enabled: boolean9("enabled").notNull().default(true),
4927
- settingsJson: jsonb26("settings_json").$type().notNull().default({}),
4928
- lastError: text50("last_error"),
4929
- createdAt: timestamp49("created_at", { withTimezone: true }).notNull().defaultNow(),
4930
- updatedAt: timestamp49("updated_at", { withTimezone: true }).notNull().defaultNow()
5074
+ id: uuid49("id").primaryKey().defaultRandom(),
5075
+ companyId: uuid49("company_id").notNull().references(() => companies.id, { onDelete: "cascade" }),
5076
+ pluginId: uuid49("plugin_id").notNull().references(() => plugins.id, { onDelete: "cascade" }),
5077
+ enabled: boolean10("enabled").notNull().default(true),
5078
+ settingsJson: jsonb27("settings_json").$type().notNull().default({}),
5079
+ lastError: text51("last_error"),
5080
+ createdAt: timestamp50("created_at", { withTimezone: true }).notNull().defaultNow(),
5081
+ updatedAt: timestamp50("updated_at", { withTimezone: true }).notNull().defaultNow()
4931
5082
  },
4932
5083
  (table) => ({
4933
- companyIdx: index44("plugin_company_settings_company_idx").on(table.companyId),
4934
- pluginIdx: index44("plugin_company_settings_plugin_idx").on(table.pluginId),
5084
+ companyIdx: index45("plugin_company_settings_company_idx").on(table.companyId),
5085
+ pluginIdx: index45("plugin_company_settings_plugin_idx").on(table.pluginId),
4935
5086
  companyPluginUq: uniqueIndex24("plugin_company_settings_company_plugin_uq").on(
4936
5087
  table.companyId,
4937
5088
  table.pluginId
@@ -4943,12 +5094,12 @@ var init_plugin_company_settings = __esm({
4943
5094
 
4944
5095
  // ../packages/db/src/schema/plugin_state.ts
4945
5096
  import {
4946
- pgTable as pgTable50,
4947
- uuid as uuid49,
4948
- text as text51,
4949
- timestamp as timestamp50,
4950
- jsonb as jsonb27,
4951
- index as index45,
5097
+ pgTable as pgTable51,
5098
+ uuid as uuid50,
5099
+ text as text52,
5100
+ timestamp as timestamp51,
5101
+ jsonb as jsonb28,
5102
+ index as index46,
4952
5103
  unique as unique2
4953
5104
  } from "drizzle-orm/pg-core";
4954
5105
  var pluginState;
@@ -4956,30 +5107,30 @@ var init_plugin_state = __esm({
4956
5107
  "../packages/db/src/schema/plugin_state.ts"() {
4957
5108
  "use strict";
4958
5109
  init_plugins();
4959
- pluginState = pgTable50(
5110
+ pluginState = pgTable51(
4960
5111
  "plugin_state",
4961
5112
  {
4962
- id: uuid49("id").primaryKey().defaultRandom(),
5113
+ id: uuid50("id").primaryKey().defaultRandom(),
4963
5114
  /** FK to the owning plugin. Cascades on delete. */
4964
- pluginId: uuid49("plugin_id").notNull().references(() => plugins.id, { onDelete: "cascade" }),
5115
+ pluginId: uuid50("plugin_id").notNull().references(() => plugins.id, { onDelete: "cascade" }),
4965
5116
  /** Granularity of the scope (e.g. `"instance"`, `"project"`, `"issue"`). */
4966
- scopeKind: text51("scope_kind").$type().notNull(),
5117
+ scopeKind: text52("scope_kind").$type().notNull(),
4967
5118
  /**
4968
5119
  * UUID or text identifier for the scoped object.
4969
5120
  * Null for `instance` scope (which has no associated entity).
4970
5121
  */
4971
- scopeId: text51("scope_id"),
5122
+ scopeId: text52("scope_id"),
4972
5123
  /**
4973
5124
  * Sub-namespace to avoid key collisions within a scope.
4974
5125
  * Defaults to `"default"` if the plugin does not specify one.
4975
5126
  */
4976
- namespace: text51("namespace").notNull().default("default"),
5127
+ namespace: text52("namespace").notNull().default("default"),
4977
5128
  /** The key identifying this state entry within the namespace. */
4978
- stateKey: text51("state_key").notNull(),
5129
+ stateKey: text52("state_key").notNull(),
4979
5130
  /** JSON-serializable value stored by the plugin. */
4980
- valueJson: jsonb27("value_json").notNull(),
5131
+ valueJson: jsonb28("value_json").notNull(),
4981
5132
  /** Timestamp of the most recent write. */
4982
- updatedAt: timestamp50("updated_at", { withTimezone: true }).notNull().defaultNow()
5133
+ updatedAt: timestamp51("updated_at", { withTimezone: true }).notNull().defaultNow()
4983
5134
  },
4984
5135
  (table) => ({
4985
5136
  /**
@@ -5001,7 +5152,7 @@ var init_plugin_state = __esm({
5001
5152
  table.stateKey
5002
5153
  ).nullsNotDistinct(),
5003
5154
  /** Speed up lookups by plugin + scope kind (most common access pattern). */
5004
- pluginScopeIdx: index45("plugin_state_plugin_scope_idx").on(
5155
+ pluginScopeIdx: index46("plugin_state_plugin_scope_idx").on(
5005
5156
  table.pluginId,
5006
5157
  table.scopeKind
5007
5158
  )
@@ -5012,12 +5163,12 @@ var init_plugin_state = __esm({
5012
5163
 
5013
5164
  // ../packages/db/src/schema/plugin_entities.ts
5014
5165
  import {
5015
- pgTable as pgTable51,
5016
- uuid as uuid50,
5017
- text as text52,
5018
- timestamp as timestamp51,
5019
- jsonb as jsonb28,
5020
- index as index46,
5166
+ pgTable as pgTable52,
5167
+ uuid as uuid51,
5168
+ text as text53,
5169
+ timestamp as timestamp52,
5170
+ jsonb as jsonb29,
5171
+ index as index47,
5021
5172
  uniqueIndex as uniqueIndex25
5022
5173
  } from "drizzle-orm/pg-core";
5023
5174
  var pluginEntities;
@@ -5025,27 +5176,27 @@ var init_plugin_entities = __esm({
5025
5176
  "../packages/db/src/schema/plugin_entities.ts"() {
5026
5177
  "use strict";
5027
5178
  init_plugins();
5028
- pluginEntities = pgTable51(
5179
+ pluginEntities = pgTable52(
5029
5180
  "plugin_entities",
5030
5181
  {
5031
- id: uuid50("id").primaryKey().defaultRandom(),
5032
- pluginId: uuid50("plugin_id").notNull().references(() => plugins.id, { onDelete: "cascade" }),
5033
- entityType: text52("entity_type").notNull(),
5034
- scopeKind: text52("scope_kind").$type().notNull(),
5035
- scopeId: text52("scope_id"),
5182
+ id: uuid51("id").primaryKey().defaultRandom(),
5183
+ pluginId: uuid51("plugin_id").notNull().references(() => plugins.id, { onDelete: "cascade" }),
5184
+ entityType: text53("entity_type").notNull(),
5185
+ scopeKind: text53("scope_kind").$type().notNull(),
5186
+ scopeId: text53("scope_id"),
5036
5187
  // NULL for global scope (text to match plugin_state.scope_id)
5037
- externalId: text52("external_id"),
5188
+ externalId: text53("external_id"),
5038
5189
  // ID in the external system
5039
- title: text52("title"),
5040
- status: text52("status"),
5041
- data: jsonb28("data").$type().notNull().default({}),
5042
- createdAt: timestamp51("created_at", { withTimezone: true }).notNull().defaultNow(),
5043
- updatedAt: timestamp51("updated_at", { withTimezone: true }).notNull().defaultNow()
5190
+ title: text53("title"),
5191
+ status: text53("status"),
5192
+ data: jsonb29("data").$type().notNull().default({}),
5193
+ createdAt: timestamp52("created_at", { withTimezone: true }).notNull().defaultNow(),
5194
+ updatedAt: timestamp52("updated_at", { withTimezone: true }).notNull().defaultNow()
5044
5195
  },
5045
5196
  (table) => ({
5046
- pluginIdx: index46("plugin_entities_plugin_idx").on(table.pluginId),
5047
- typeIdx: index46("plugin_entities_type_idx").on(table.entityType),
5048
- scopeIdx: index46("plugin_entities_scope_idx").on(table.scopeKind, table.scopeId),
5197
+ pluginIdx: index47("plugin_entities_plugin_idx").on(table.pluginId),
5198
+ typeIdx: index47("plugin_entities_type_idx").on(table.entityType),
5199
+ scopeIdx: index47("plugin_entities_scope_idx").on(table.scopeKind, table.scopeId),
5049
5200
  externalIdx: uniqueIndex25("plugin_entities_external_idx").on(
5050
5201
  table.pluginId,
5051
5202
  table.entityType,
@@ -5058,13 +5209,13 @@ var init_plugin_entities = __esm({
5058
5209
 
5059
5210
  // ../packages/db/src/schema/plugin_jobs.ts
5060
5211
  import {
5061
- pgTable as pgTable52,
5062
- uuid as uuid51,
5063
- text as text53,
5212
+ pgTable as pgTable53,
5213
+ uuid as uuid52,
5214
+ text as text54,
5064
5215
  integer as integer19,
5065
- timestamp as timestamp52,
5066
- jsonb as jsonb29,
5067
- index as index47,
5216
+ timestamp as timestamp53,
5217
+ jsonb as jsonb30,
5218
+ index as index48,
5068
5219
  uniqueIndex as uniqueIndex26
5069
5220
  } from "drizzle-orm/pg-core";
5070
5221
  var pluginJobs, pluginJobRuns;
@@ -5072,57 +5223,57 @@ var init_plugin_jobs = __esm({
5072
5223
  "../packages/db/src/schema/plugin_jobs.ts"() {
5073
5224
  "use strict";
5074
5225
  init_plugins();
5075
- pluginJobs = pgTable52(
5226
+ pluginJobs = pgTable53(
5076
5227
  "plugin_jobs",
5077
5228
  {
5078
- id: uuid51("id").primaryKey().defaultRandom(),
5229
+ id: uuid52("id").primaryKey().defaultRandom(),
5079
5230
  /** FK to the owning plugin. Cascades on delete. */
5080
- pluginId: uuid51("plugin_id").notNull().references(() => plugins.id, { onDelete: "cascade" }),
5231
+ pluginId: uuid52("plugin_id").notNull().references(() => plugins.id, { onDelete: "cascade" }),
5081
5232
  /** Identifier matching the key in the plugin manifest's `jobs` array. */
5082
- jobKey: text53("job_key").notNull(),
5233
+ jobKey: text54("job_key").notNull(),
5083
5234
  /** Cron expression (e.g. `"0 * * * *"`) or interval string. */
5084
- schedule: text53("schedule").notNull(),
5235
+ schedule: text54("schedule").notNull(),
5085
5236
  /** Current scheduling state. */
5086
- status: text53("status").$type().notNull().default("active"),
5237
+ status: text54("status").$type().notNull().default("active"),
5087
5238
  /** Timestamp of the most recent successful execution. */
5088
- lastRunAt: timestamp52("last_run_at", { withTimezone: true }),
5239
+ lastRunAt: timestamp53("last_run_at", { withTimezone: true }),
5089
5240
  /** Pre-computed timestamp of the next scheduled execution. */
5090
- nextRunAt: timestamp52("next_run_at", { withTimezone: true }),
5091
- createdAt: timestamp52("created_at", { withTimezone: true }).notNull().defaultNow(),
5092
- updatedAt: timestamp52("updated_at", { withTimezone: true }).notNull().defaultNow()
5241
+ nextRunAt: timestamp53("next_run_at", { withTimezone: true }),
5242
+ createdAt: timestamp53("created_at", { withTimezone: true }).notNull().defaultNow(),
5243
+ updatedAt: timestamp53("updated_at", { withTimezone: true }).notNull().defaultNow()
5093
5244
  },
5094
5245
  (table) => ({
5095
- pluginIdx: index47("plugin_jobs_plugin_idx").on(table.pluginId),
5096
- nextRunIdx: index47("plugin_jobs_next_run_idx").on(table.nextRunAt),
5246
+ pluginIdx: index48("plugin_jobs_plugin_idx").on(table.pluginId),
5247
+ nextRunIdx: index48("plugin_jobs_next_run_idx").on(table.nextRunAt),
5097
5248
  uniqueJobIdx: uniqueIndex26("plugin_jobs_unique_idx").on(table.pluginId, table.jobKey)
5098
5249
  })
5099
5250
  );
5100
- pluginJobRuns = pgTable52(
5251
+ pluginJobRuns = pgTable53(
5101
5252
  "plugin_job_runs",
5102
5253
  {
5103
- id: uuid51("id").primaryKey().defaultRandom(),
5254
+ id: uuid52("id").primaryKey().defaultRandom(),
5104
5255
  /** FK to the parent job definition. Cascades on delete. */
5105
- jobId: uuid51("job_id").notNull().references(() => pluginJobs.id, { onDelete: "cascade" }),
5256
+ jobId: uuid52("job_id").notNull().references(() => pluginJobs.id, { onDelete: "cascade" }),
5106
5257
  /** Denormalized FK to the owning plugin for efficient querying. Cascades on delete. */
5107
- pluginId: uuid51("plugin_id").notNull().references(() => plugins.id, { onDelete: "cascade" }),
5258
+ pluginId: uuid52("plugin_id").notNull().references(() => plugins.id, { onDelete: "cascade" }),
5108
5259
  /** What caused this run to start (`"scheduled"` or `"manual"`). */
5109
- trigger: text53("trigger").$type().notNull(),
5260
+ trigger: text54("trigger").$type().notNull(),
5110
5261
  /** Current lifecycle state of this run. */
5111
- status: text53("status").$type().notNull().default("pending"),
5262
+ status: text54("status").$type().notNull().default("pending"),
5112
5263
  /** Wall-clock duration in milliseconds. Null until the run finishes. */
5113
5264
  durationMs: integer19("duration_ms"),
5114
5265
  /** Error message if `status === "failed"`. */
5115
- error: text53("error"),
5266
+ error: text54("error"),
5116
5267
  /** Ordered list of log lines emitted during this run. */
5117
- logs: jsonb29("logs").$type().notNull().default([]),
5118
- startedAt: timestamp52("started_at", { withTimezone: true }),
5119
- finishedAt: timestamp52("finished_at", { withTimezone: true }),
5120
- createdAt: timestamp52("created_at", { withTimezone: true }).notNull().defaultNow()
5268
+ logs: jsonb30("logs").$type().notNull().default([]),
5269
+ startedAt: timestamp53("started_at", { withTimezone: true }),
5270
+ finishedAt: timestamp53("finished_at", { withTimezone: true }),
5271
+ createdAt: timestamp53("created_at", { withTimezone: true }).notNull().defaultNow()
5121
5272
  },
5122
5273
  (table) => ({
5123
- jobIdx: index47("plugin_job_runs_job_idx").on(table.jobId),
5124
- pluginIdx: index47("plugin_job_runs_plugin_idx").on(table.pluginId),
5125
- statusIdx: index47("plugin_job_runs_status_idx").on(table.status)
5274
+ jobIdx: index48("plugin_job_runs_job_idx").on(table.jobId),
5275
+ pluginIdx: index48("plugin_job_runs_plugin_idx").on(table.pluginId),
5276
+ statusIdx: index48("plugin_job_runs_status_idx").on(table.status)
5126
5277
  })
5127
5278
  );
5128
5279
  }
@@ -5130,47 +5281,47 @@ var init_plugin_jobs = __esm({
5130
5281
 
5131
5282
  // ../packages/db/src/schema/plugin_webhooks.ts
5132
5283
  import {
5133
- pgTable as pgTable53,
5134
- uuid as uuid52,
5135
- text as text54,
5284
+ pgTable as pgTable54,
5285
+ uuid as uuid53,
5286
+ text as text55,
5136
5287
  integer as integer20,
5137
- timestamp as timestamp53,
5138
- jsonb as jsonb30,
5139
- index as index48
5288
+ timestamp as timestamp54,
5289
+ jsonb as jsonb31,
5290
+ index as index49
5140
5291
  } from "drizzle-orm/pg-core";
5141
5292
  var pluginWebhookDeliveries;
5142
5293
  var init_plugin_webhooks = __esm({
5143
5294
  "../packages/db/src/schema/plugin_webhooks.ts"() {
5144
5295
  "use strict";
5145
5296
  init_plugins();
5146
- pluginWebhookDeliveries = pgTable53(
5297
+ pluginWebhookDeliveries = pgTable54(
5147
5298
  "plugin_webhook_deliveries",
5148
5299
  {
5149
- id: uuid52("id").primaryKey().defaultRandom(),
5300
+ id: uuid53("id").primaryKey().defaultRandom(),
5150
5301
  /** FK to the owning plugin. Cascades on delete. */
5151
- pluginId: uuid52("plugin_id").notNull().references(() => plugins.id, { onDelete: "cascade" }),
5302
+ pluginId: uuid53("plugin_id").notNull().references(() => plugins.id, { onDelete: "cascade" }),
5152
5303
  /** Identifier matching the key in the plugin manifest's `webhooks` array. */
5153
- webhookKey: text54("webhook_key").notNull(),
5304
+ webhookKey: text55("webhook_key").notNull(),
5154
5305
  /** Optional de-duplication ID provided by the external system. */
5155
- externalId: text54("external_id"),
5306
+ externalId: text55("external_id"),
5156
5307
  /** Current delivery state. */
5157
- status: text54("status").$type().notNull().default("pending"),
5308
+ status: text55("status").$type().notNull().default("pending"),
5158
5309
  /** Wall-clock processing duration in milliseconds. Null until delivery finishes. */
5159
5310
  durationMs: integer20("duration_ms"),
5160
5311
  /** Error message if `status === "failed"`. */
5161
- error: text54("error"),
5312
+ error: text55("error"),
5162
5313
  /** Raw JSON body of the inbound HTTP request. */
5163
- payload: jsonb30("payload").$type().notNull(),
5314
+ payload: jsonb31("payload").$type().notNull(),
5164
5315
  /** Relevant HTTP headers from the inbound request (e.g. signature headers). */
5165
- headers: jsonb30("headers").$type().notNull().default({}),
5166
- startedAt: timestamp53("started_at", { withTimezone: true }),
5167
- finishedAt: timestamp53("finished_at", { withTimezone: true }),
5168
- createdAt: timestamp53("created_at", { withTimezone: true }).notNull().defaultNow()
5316
+ headers: jsonb31("headers").$type().notNull().default({}),
5317
+ startedAt: timestamp54("started_at", { withTimezone: true }),
5318
+ finishedAt: timestamp54("finished_at", { withTimezone: true }),
5319
+ createdAt: timestamp54("created_at", { withTimezone: true }).notNull().defaultNow()
5169
5320
  },
5170
5321
  (table) => ({
5171
- pluginIdx: index48("plugin_webhook_deliveries_plugin_idx").on(table.pluginId),
5172
- statusIdx: index48("plugin_webhook_deliveries_status_idx").on(table.status),
5173
- keyIdx: index48("plugin_webhook_deliveries_key_idx").on(table.webhookKey)
5322
+ pluginIdx: index49("plugin_webhook_deliveries_plugin_idx").on(table.pluginId),
5323
+ statusIdx: index49("plugin_webhook_deliveries_status_idx").on(table.status),
5324
+ keyIdx: index49("plugin_webhook_deliveries_key_idx").on(table.webhookKey)
5174
5325
  })
5175
5326
  );
5176
5327
  }
@@ -5178,34 +5329,34 @@ var init_plugin_webhooks = __esm({
5178
5329
 
5179
5330
  // ../packages/db/src/schema/plugin_logs.ts
5180
5331
  import {
5181
- pgTable as pgTable54,
5182
- uuid as uuid53,
5183
- text as text55,
5184
- timestamp as timestamp54,
5185
- jsonb as jsonb31,
5186
- index as index49
5332
+ pgTable as pgTable55,
5333
+ uuid as uuid54,
5334
+ text as text56,
5335
+ timestamp as timestamp55,
5336
+ jsonb as jsonb32,
5337
+ index as index50
5187
5338
  } from "drizzle-orm/pg-core";
5188
5339
  var pluginLogs;
5189
5340
  var init_plugin_logs = __esm({
5190
5341
  "../packages/db/src/schema/plugin_logs.ts"() {
5191
5342
  "use strict";
5192
5343
  init_plugins();
5193
- pluginLogs = pgTable54(
5344
+ pluginLogs = pgTable55(
5194
5345
  "plugin_logs",
5195
5346
  {
5196
- id: uuid53("id").primaryKey().defaultRandom(),
5197
- pluginId: uuid53("plugin_id").notNull().references(() => plugins.id, { onDelete: "cascade" }),
5198
- level: text55("level").notNull().default("info"),
5199
- message: text55("message").notNull(),
5200
- meta: jsonb31("meta").$type(),
5201
- createdAt: timestamp54("created_at", { withTimezone: true }).notNull().defaultNow()
5347
+ id: uuid54("id").primaryKey().defaultRandom(),
5348
+ pluginId: uuid54("plugin_id").notNull().references(() => plugins.id, { onDelete: "cascade" }),
5349
+ level: text56("level").notNull().default("info"),
5350
+ message: text56("message").notNull(),
5351
+ meta: jsonb32("meta").$type(),
5352
+ createdAt: timestamp55("created_at", { withTimezone: true }).notNull().defaultNow()
5202
5353
  },
5203
5354
  (table) => ({
5204
- pluginTimeIdx: index49("plugin_logs_plugin_time_idx").on(
5355
+ pluginTimeIdx: index50("plugin_logs_plugin_time_idx").on(
5205
5356
  table.pluginId,
5206
5357
  table.createdAt
5207
5358
  ),
5208
- levelIdx: index49("plugin_logs_level_idx").on(table.level)
5359
+ levelIdx: index50("plugin_logs_level_idx").on(table.level)
5209
5360
  })
5210
5361
  );
5211
5362
  }
@@ -5255,6 +5406,7 @@ __export(schema_exports, {
5255
5406
  issueWorkProducts: () => issueWorkProducts,
5256
5407
  issues: () => issues,
5257
5408
  joinRequests: () => joinRequests,
5409
+ kbSkillDocs: () => kbSkillDocs,
5258
5410
  labels: () => labels,
5259
5411
  pluginCompanySettings: () => pluginCompanySettings,
5260
5412
  pluginConfig: () => pluginConfig,
@@ -5311,6 +5463,7 @@ var init_schema2 = __esm({
5311
5463
  init_assets();
5312
5464
  init_issue_attachments();
5313
5465
  init_documents();
5466
+ init_kb_skill_docs();
5314
5467
  init_document_revisions();
5315
5468
  init_issue_documents();
5316
5469
  init_heartbeat_runs();
@@ -5912,7 +6065,7 @@ function sanitizeRestoreErrorMessage(error) {
5912
6065
  }
5913
6066
  return error instanceof Error ? error.message : String(error);
5914
6067
  }
5915
- function timestamp55(date2 = /* @__PURE__ */ new Date()) {
6068
+ function timestamp56(date2 = /* @__PURE__ */ new Date()) {
5916
6069
  const pad = (n) => String(n).padStart(2, "0");
5917
6070
  return `${date2.getFullYear()}${pad(date2.getMonth() + 1)}${pad(date2.getDate())}-${pad(date2.getHours())}${pad(date2.getMinutes())}${pad(date2.getSeconds())}`;
5918
6071
  }
@@ -6115,9 +6268,9 @@ async function runDatabaseBackup(opts) {
6115
6268
  WHERE n.nspname = ${schema_name} AND t.relname = ${tablename} AND c.contype = 'p'
6116
6269
  GROUP BY c.conname
6117
6270
  `;
6118
- for (const p16 of pk) {
6119
- const cols = p16.column_names.map((c) => `"${c}"`).join(", ");
6120
- colDefs.push(` CONSTRAINT "${p16.constraint_name}" PRIMARY KEY (${cols})`);
6271
+ for (const p19 of pk) {
6272
+ const cols = p19.column_names.map((c) => `"${c}"`).join(", ");
6273
+ colDefs.push(` CONSTRAINT "${p19.constraint_name}" PRIMARY KEY (${cols})`);
6121
6274
  }
6122
6275
  emit(`CREATE TABLE ${qualifiedTableName} (`);
6123
6276
  emit(colDefs.join(",\n"));
@@ -6236,8 +6389,8 @@ async function runDatabaseBackup(opts) {
6236
6389
  const rows = await sql2.unsafe(`SELECT * FROM ${qualifiedTableName}`).values();
6237
6390
  const nullifiedColumns = nullifiedColumnsByTable.get(tablename) ?? /* @__PURE__ */ new Set();
6238
6391
  for (const row of rows) {
6239
- const values = row.map((rawValue, index50) => {
6240
- const columnName = cols[index50]?.column_name;
6392
+ const values = row.map((rawValue, index51) => {
6393
+ const columnName = cols[index51]?.column_name;
6241
6394
  const val = columnName && nullifiedColumns.has(columnName) ? null : rawValue;
6242
6395
  if (val === null || val === void 0) return "NULL";
6243
6396
  if (typeof val === "boolean") return val ? "true" : "false";
@@ -6267,7 +6420,7 @@ async function runDatabaseBackup(opts) {
6267
6420
  emitStatement("COMMIT;");
6268
6421
  emit("");
6269
6422
  mkdirSync(opts.backupDir, { recursive: true });
6270
- const backupFile = resolve(opts.backupDir, `${filenamePrefix}-${timestamp55()}.sql`);
6423
+ const backupFile = resolve(opts.backupDir, `${filenamePrefix}-${timestamp56()}.sql`);
6271
6424
  await writeFile(backupFile, lines.join("\n"), "utf8");
6272
6425
  const sizeBytes = statSync(backupFile).size;
6273
6426
  const prunedCount = pruneOldBackups(opts.backupDir, retentionDays, filenamePrefix);
@@ -6364,6 +6517,7 @@ __export(src_exports, {
6364
6517
  issueWorkProducts: () => issueWorkProducts,
6365
6518
  issues: () => issues,
6366
6519
  joinRequests: () => joinRequests,
6520
+ kbSkillDocs: () => kbSkillDocs,
6367
6521
  labels: () => labels,
6368
6522
  migratePostgresIfEmpty: () => migratePostgresIfEmpty,
6369
6523
  pluginCompanySettings: () => pluginCompanySettings,
@@ -7862,6 +8016,9 @@ var init_onboard = __esm({
7862
8016
  init_onboard();
7863
8017
  init_doctor();
7864
8018
  import { Command } from "commander";
8019
+ import * as p18 from "@clack/prompts";
8020
+ import fs16 from "node:fs";
8021
+ import path23 from "node:path";
7865
8022
 
7866
8023
  // src/commands/env.ts
7867
8024
  init_store();
@@ -8231,24 +8388,30 @@ ${err instanceof Error ? err.message : String(err)}`
8231
8388
  p12.outro("");
8232
8389
  return;
8233
8390
  }
8234
- let continueLoop = true;
8235
- while (continueLoop) {
8236
- if (!section) {
8237
- const choice = await p12.select({
8238
- message: "Which section do you want to configure?",
8239
- options: Object.entries(SECTION_LABELS).map(([value, label]) => ({
8240
- value,
8241
- label
8242
- }))
8243
- });
8244
- if (p12.isCancel(choice)) {
8245
- p12.cancel("Configuration cancelled.");
8246
- return;
8247
- }
8248
- section = choice;
8391
+ let sectionsToConfigure;
8392
+ if (section) {
8393
+ sectionsToConfigure = [section];
8394
+ } else {
8395
+ const choices = await p12.multiselect({
8396
+ message: "Which sections do you want to configure?",
8397
+ options: Object.entries(SECTION_LABELS).map(([value, label]) => ({
8398
+ value,
8399
+ label
8400
+ }))
8401
+ });
8402
+ if (p12.isCancel(choices)) {
8403
+ p12.cancel("Configuration cancelled.");
8404
+ return;
8405
+ }
8406
+ sectionsToConfigure = choices;
8407
+ if (sectionsToConfigure.length === 0) {
8408
+ p12.cancel("No sections selected.");
8409
+ return;
8249
8410
  }
8250
- p12.log.step(pc7.bold(SECTION_LABELS[section]));
8251
- switch (section) {
8411
+ }
8412
+ for (const selectedSection of sectionsToConfigure) {
8413
+ p12.log.step(pc7.bold(SECTION_LABELS[selectedSection]));
8414
+ switch (selectedSection) {
8252
8415
  case "database":
8253
8416
  config.database = await promptDatabase(config.database);
8254
8417
  break;
@@ -8296,20 +8459,7 @@ ${err instanceof Error ? err.message : String(err)}`
8296
8459
  config.$meta.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
8297
8460
  config.$meta.source = "configure";
8298
8461
  writeConfig(config, opts.config);
8299
- p12.log.success(`${SECTION_LABELS[section]} configuration updated.`);
8300
- if (opts.section) {
8301
- continueLoop = false;
8302
- } else {
8303
- const another = await p12.confirm({
8304
- message: "Configure another section?",
8305
- initialValue: false
8306
- });
8307
- if (p12.isCancel(another) || !another) {
8308
- continueLoop = false;
8309
- } else {
8310
- section = void 0;
8311
- }
8312
- }
8462
+ p12.log.success(`${SECTION_LABELS[selectedSection]} configuration updated.`);
8313
8463
  }
8314
8464
  p12.outro("Configuration saved.");
8315
8465
  }
@@ -8392,8 +8542,8 @@ function printClaudeStreamEvent(raw, debug) {
8392
8542
  const block = blockRaw;
8393
8543
  const blockType = typeof block.type === "string" ? block.type : "";
8394
8544
  if (blockType === "text") {
8395
- const text56 = typeof block.text === "string" ? block.text : "";
8396
- if (text56) console.log(pc9.green(`assistant: ${text56}`));
8545
+ const text58 = typeof block.text === "string" ? block.text : "";
8546
+ if (text58) console.log(pc9.green(`assistant: ${text58}`));
8397
8547
  } else if (blockType === "tool_use") {
8398
8548
  const name = typeof block.name === "string" ? block.name : "unknown";
8399
8549
  console.log(pc9.yellow(`tool_call: ${name}`));
@@ -8485,13 +8635,13 @@ function printItemStarted(item) {
8485
8635
  function printItemCompleted(item) {
8486
8636
  const itemType = asString(item.type);
8487
8637
  if (itemType === "agent_message") {
8488
- const text56 = asString(item.text);
8489
- if (text56) console.log(pc10.green(`assistant: ${text56}`));
8638
+ const text58 = asString(item.text);
8639
+ if (text58) console.log(pc10.green(`assistant: ${text58}`));
8490
8640
  return true;
8491
8641
  }
8492
8642
  if (itemType === "reasoning") {
8493
- const text56 = asString(item.text);
8494
- if (text56) console.log(pc10.gray(`thinking: ${text56}`));
8643
+ const text58 = asString(item.text);
8644
+ if (text58) console.log(pc10.gray(`thinking: ${text58}`));
8495
8645
  return true;
8496
8646
  }
8497
8647
  if (itemType === "tool_use") {
@@ -8526,8 +8676,8 @@ function printItemCompleted(item) {
8526
8676
  const changes = Array.isArray(item.changes) ? item.changes : [];
8527
8677
  const entries = changes.map((changeRaw) => asRecord(changeRaw)).filter((change) => Boolean(change)).map((change) => {
8528
8678
  const kind = asString(change.kind, "update");
8529
- const path19 = asString(change.path, "unknown");
8530
- return `${kind} ${path19}`;
8679
+ const path24 = asString(change.path, "unknown");
8680
+ return `${kind} ${path24}`;
8531
8681
  });
8532
8682
  const preview = entries.length > 0 ? entries.slice(0, 6).join(", ") : "none";
8533
8683
  const more = entries.length > 6 ? ` (+${entries.length - 6} more)` : "";
@@ -8541,9 +8691,9 @@ function printItemCompleted(item) {
8541
8691
  }
8542
8692
  if (itemType === "tool_result") {
8543
8693
  const isError = item.is_error === true || asString(item.status) === "error";
8544
- const text56 = asString(item.content) || asString(item.result) || asString(item.output);
8694
+ const text58 = asString(item.content) || asString(item.result) || asString(item.output);
8545
8695
  console.log((isError ? pc10.red : pc10.cyan)(`tool_result${isError ? " (error)" : ""}`));
8546
- if (text56) console.log((isError ? pc10.red : pc10.gray)(text56));
8696
+ if (text58) console.log((isError ? pc10.red : pc10.gray)(text58));
8547
8697
  return true;
8548
8698
  }
8549
8699
  return false;
@@ -8624,13 +8774,14 @@ function printCodexStreamEvent(raw, _debug) {
8624
8774
  console.log(line);
8625
8775
  }
8626
8776
 
8627
- // ../packages/adapters/cursor-local/src/cli/format-event.ts
8777
+ // ../../node_modules/@paperclipai/adapter-cursor-local/dist/cli/format-event.js
8628
8778
  import pc11 from "picocolors";
8629
8779
 
8630
- // ../packages/adapters/cursor-local/src/shared/stream.ts
8780
+ // ../../node_modules/@paperclipai/adapter-cursor-local/dist/shared/stream.js
8631
8781
  function normalizeCursorStreamLine(rawLine) {
8632
8782
  const trimmed = rawLine.trim();
8633
- if (!trimmed) return { stream: null, line: "" };
8783
+ if (!trimmed)
8784
+ return { stream: null, line: "" };
8634
8785
  const prefixed = trimmed.match(/^(stdout|stderr)\s*[:=]?\s*([\[{].*)$/i);
8635
8786
  if (!prefixed) {
8636
8787
  return { stream: null, line: trimmed };
@@ -8640,9 +8791,10 @@ function normalizeCursorStreamLine(rawLine) {
8640
8791
  return { stream, line };
8641
8792
  }
8642
8793
 
8643
- // ../packages/adapters/cursor-local/src/cli/format-event.ts
8794
+ // ../../node_modules/@paperclipai/adapter-cursor-local/dist/cli/format-event.js
8644
8795
  function asRecord2(value) {
8645
- if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
8796
+ if (typeof value !== "object" || value === null || Array.isArray(value))
8797
+ return null;
8646
8798
  return value;
8647
8799
  }
8648
8800
  function asString2(value, fallback = "") {
@@ -8652,8 +8804,10 @@ function asNumber2(value, fallback = 0) {
8652
8804
  return typeof value === "number" && Number.isFinite(value) ? value : fallback;
8653
8805
  }
8654
8806
  function stringifyUnknown(value) {
8655
- if (typeof value === "string") return value;
8656
- if (value === null || value === void 0) return "";
8807
+ if (typeof value === "string")
8808
+ return value;
8809
+ if (value === null || value === void 0)
8810
+ return "";
8657
8811
  try {
8658
8812
  return JSON.stringify(value, null, 2);
8659
8813
  } catch {
@@ -8662,47 +8816,59 @@ function stringifyUnknown(value) {
8662
8816
  }
8663
8817
  function printUserMessage(messageRaw) {
8664
8818
  if (typeof messageRaw === "string") {
8665
- const text56 = messageRaw.trim();
8666
- if (text56) console.log(pc11.gray(`user: ${text56}`));
8819
+ const text58 = messageRaw.trim();
8820
+ if (text58)
8821
+ console.log(pc11.gray(`user: ${text58}`));
8667
8822
  return;
8668
8823
  }
8669
8824
  const message = asRecord2(messageRaw);
8670
- if (!message) return;
8825
+ if (!message)
8826
+ return;
8671
8827
  const directText = asString2(message.text).trim();
8672
- if (directText) console.log(pc11.gray(`user: ${directText}`));
8828
+ if (directText)
8829
+ console.log(pc11.gray(`user: ${directText}`));
8673
8830
  const content = Array.isArray(message.content) ? message.content : [];
8674
8831
  for (const partRaw of content) {
8675
8832
  const part = asRecord2(partRaw);
8676
- if (!part) continue;
8833
+ if (!part)
8834
+ continue;
8677
8835
  const type = asString2(part.type).trim();
8678
- if (type !== "output_text" && type !== "text") continue;
8679
- const text56 = asString2(part.text).trim();
8680
- if (text56) console.log(pc11.gray(`user: ${text56}`));
8836
+ if (type !== "output_text" && type !== "text")
8837
+ continue;
8838
+ const text58 = asString2(part.text).trim();
8839
+ if (text58)
8840
+ console.log(pc11.gray(`user: ${text58}`));
8681
8841
  }
8682
8842
  }
8683
8843
  function printAssistantMessage(messageRaw) {
8684
8844
  if (typeof messageRaw === "string") {
8685
- const text56 = messageRaw.trim();
8686
- if (text56) console.log(pc11.green(`assistant: ${text56}`));
8845
+ const text58 = messageRaw.trim();
8846
+ if (text58)
8847
+ console.log(pc11.green(`assistant: ${text58}`));
8687
8848
  return;
8688
8849
  }
8689
8850
  const message = asRecord2(messageRaw);
8690
- if (!message) return;
8851
+ if (!message)
8852
+ return;
8691
8853
  const directText = asString2(message.text).trim();
8692
- if (directText) console.log(pc11.green(`assistant: ${directText}`));
8854
+ if (directText)
8855
+ console.log(pc11.green(`assistant: ${directText}`));
8693
8856
  const content = Array.isArray(message.content) ? message.content : [];
8694
8857
  for (const partRaw of content) {
8695
8858
  const part = asRecord2(partRaw);
8696
- if (!part) continue;
8859
+ if (!part)
8860
+ continue;
8697
8861
  const type = asString2(part.type).trim();
8698
8862
  if (type === "output_text" || type === "text") {
8699
- const text56 = asString2(part.text).trim();
8700
- if (text56) console.log(pc11.green(`assistant: ${text56}`));
8863
+ const text58 = asString2(part.text).trim();
8864
+ if (text58)
8865
+ console.log(pc11.green(`assistant: ${text58}`));
8701
8866
  continue;
8702
8867
  }
8703
8868
  if (type === "thinking") {
8704
- const text56 = asString2(part.text).trim();
8705
- if (text56) console.log(pc11.gray(`thinking: ${text56}`));
8869
+ const text58 = asString2(part.text).trim();
8870
+ if (text58)
8871
+ console.log(pc11.gray(`thinking: ${text58}`));
8706
8872
  continue;
8707
8873
  }
8708
8874
  if (type === "tool_call") {
@@ -8722,7 +8888,8 @@ function printAssistantMessage(messageRaw) {
8722
8888
  const isError = part.is_error === true || asString2(part.status).toLowerCase() === "error";
8723
8889
  const contentText = asString2(part.output) || asString2(part.text) || asString2(part.result) || stringifyUnknown(part.output ?? part.result ?? part.text ?? part);
8724
8890
  console.log((isError ? pc11.red : pc11.cyan)(`tool_result${isError ? " (error)" : ""}`));
8725
- if (contentText) console.log((isError ? pc11.red : pc11.gray)(contentText));
8891
+ if (contentText)
8892
+ console.log((isError ? pc11.red : pc11.gray)(contentText));
8726
8893
  }
8727
8894
  }
8728
8895
  }
@@ -8792,7 +8959,8 @@ function printLegacyToolEvent(part) {
8792
8959
  }
8793
8960
  function printCursorStreamEvent(raw, _debug) {
8794
8961
  const line = normalizeCursorStreamLine(raw).line;
8795
- if (!line) return;
8962
+ if (!line)
8963
+ return;
8796
8964
  let parsed = null;
8797
8965
  try {
8798
8966
  parsed = JSON.parse(line);
@@ -8822,8 +8990,9 @@ function printCursorStreamEvent(raw, _debug) {
8822
8990
  return;
8823
8991
  }
8824
8992
  if (type === "thinking") {
8825
- const text56 = asString2(parsed.text).trim() || asString2(asRecord2(parsed.delta)?.text).trim();
8826
- if (text56) console.log(pc11.gray(`thinking: ${text56}`));
8993
+ const text58 = asString2(parsed.text).trim() || asString2(asRecord2(parsed.delta)?.text).trim();
8994
+ if (text58)
8995
+ console.log(pc11.gray(`thinking: ${text58}`));
8827
8996
  return;
8828
8997
  }
8829
8998
  if (type === "tool_call") {
@@ -8834,19 +9003,18 @@ function printCursorStreamEvent(raw, _debug) {
8834
9003
  const usage = asRecord2(parsed.usage);
8835
9004
  const input = asNumber2(usage?.input_tokens, asNumber2(usage?.inputTokens));
8836
9005
  const output = asNumber2(usage?.output_tokens, asNumber2(usage?.outputTokens));
8837
- const cached = asNumber2(
8838
- usage?.cached_input_tokens,
8839
- asNumber2(usage?.cachedInputTokens, asNumber2(usage?.cache_read_input_tokens))
8840
- );
9006
+ const cached = asNumber2(usage?.cached_input_tokens, asNumber2(usage?.cachedInputTokens, asNumber2(usage?.cache_read_input_tokens)));
8841
9007
  const cost = asNumber2(parsed.total_cost_usd, asNumber2(parsed.cost_usd, asNumber2(parsed.cost)));
8842
9008
  const subtype = asString2(parsed.subtype, "result");
8843
9009
  const isError = parsed.is_error === true || subtype === "error" || subtype === "failed";
8844
9010
  console.log(pc11.blue(`result: subtype=${subtype}`));
8845
9011
  console.log(pc11.blue(`tokens: in=${input} out=${output} cached=${cached} cost=$${cost.toFixed(6)}`));
8846
9012
  const resultText = asString2(parsed.result).trim();
8847
- if (resultText) console.log((isError ? pc11.red : pc11.green)(`assistant: ${resultText}`));
9013
+ if (resultText)
9014
+ console.log((isError ? pc11.red : pc11.green)(`assistant: ${resultText}`));
8848
9015
  const errors = Array.isArray(parsed.errors) ? parsed.errors.map((value) => stringifyUnknown(value)).filter(Boolean) : [];
8849
- if (errors.length > 0) console.log(pc11.red(`errors: ${errors.join(" | ")}`));
9016
+ if (errors.length > 0)
9017
+ console.log(pc11.red(`errors: ${errors.join(" | ")}`));
8850
9018
  return;
8851
9019
  }
8852
9020
  if (type === "error") {
@@ -8861,8 +9029,9 @@ function printCursorStreamEvent(raw, _debug) {
8861
9029
  }
8862
9030
  if (type === "text") {
8863
9031
  const part = asRecord2(parsed.part);
8864
- const text56 = asString2(part?.text);
8865
- if (text56) console.log(pc11.green(`assistant: ${text56}`));
9032
+ const text58 = asString2(part?.text);
9033
+ if (text58)
9034
+ console.log(pc11.green(`assistant: ${text58}`));
8866
9035
  return;
8867
9036
  }
8868
9037
  if (type === "tool_use") {
@@ -8890,10 +9059,11 @@ function printCursorStreamEvent(raw, _debug) {
8890
9059
  console.log(line);
8891
9060
  }
8892
9061
 
8893
- // ../packages/adapters/gemini-local/src/cli/format-event.ts
9062
+ // ../../node_modules/@paperclipai/adapter-gemini-local/dist/cli/format-event.js
8894
9063
  import pc12 from "picocolors";
8895
9064
  function asRecord3(value) {
8896
- if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
9065
+ if (typeof value !== "object" || value === null || Array.isArray(value))
9066
+ return null;
8897
9067
  return value;
8898
9068
  }
8899
9069
  function asString3(value, fallback = "") {
@@ -8903,8 +9073,10 @@ function asNumber3(value, fallback = 0) {
8903
9073
  return typeof value === "number" && Number.isFinite(value) ? value : fallback;
8904
9074
  }
8905
9075
  function stringifyUnknown2(value) {
8906
- if (typeof value === "string") return value;
8907
- if (value === null || value === void 0) return "";
9076
+ if (typeof value === "string")
9077
+ return value;
9078
+ if (value === null || value === void 0)
9079
+ return "";
8908
9080
  try {
8909
9081
  return JSON.stringify(value, null, 2);
8910
9082
  } catch {
@@ -8912,11 +9084,14 @@ function stringifyUnknown2(value) {
8912
9084
  }
8913
9085
  }
8914
9086
  function errorText2(value) {
8915
- if (typeof value === "string") return value;
9087
+ if (typeof value === "string")
9088
+ return value;
8916
9089
  const rec = asRecord3(value);
8917
- if (!rec) return "";
9090
+ if (!rec)
9091
+ return "";
8918
9092
  const msg = typeof rec.message === "string" && rec.message || typeof rec.error === "string" && rec.error || typeof rec.code === "string" && rec.code || "";
8919
- if (msg) return msg;
9093
+ if (msg)
9094
+ return msg;
8920
9095
  try {
8921
9096
  return JSON.stringify(rec);
8922
9097
  } catch {
@@ -8925,41 +9100,49 @@ function errorText2(value) {
8925
9100
  }
8926
9101
  function printTextMessage(prefix, colorize, messageRaw) {
8927
9102
  if (typeof messageRaw === "string") {
8928
- const text56 = messageRaw.trim();
8929
- if (text56) console.log(colorize(`${prefix}: ${text56}`));
9103
+ const text58 = messageRaw.trim();
9104
+ if (text58)
9105
+ console.log(colorize(`${prefix}: ${text58}`));
8930
9106
  return;
8931
9107
  }
8932
9108
  const message = asRecord3(messageRaw);
8933
- if (!message) return;
9109
+ if (!message)
9110
+ return;
8934
9111
  const directText = asString3(message.text).trim();
8935
- if (directText) console.log(colorize(`${prefix}: ${directText}`));
9112
+ if (directText)
9113
+ console.log(colorize(`${prefix}: ${directText}`));
8936
9114
  const content = Array.isArray(message.content) ? message.content : [];
8937
9115
  for (const partRaw of content) {
8938
9116
  const part = asRecord3(partRaw);
8939
- if (!part) continue;
9117
+ if (!part)
9118
+ continue;
8940
9119
  const type = asString3(part.type).trim();
8941
9120
  if (type === "output_text" || type === "text" || type === "content") {
8942
- const text56 = asString3(part.text).trim() || asString3(part.content).trim();
8943
- if (text56) console.log(colorize(`${prefix}: ${text56}`));
9121
+ const text58 = asString3(part.text).trim() || asString3(part.content).trim();
9122
+ if (text58)
9123
+ console.log(colorize(`${prefix}: ${text58}`));
8944
9124
  continue;
8945
9125
  }
8946
9126
  if (type === "thinking") {
8947
- const text56 = asString3(part.text).trim();
8948
- if (text56) console.log(pc12.gray(`thinking: ${text56}`));
9127
+ const text58 = asString3(part.text).trim();
9128
+ if (text58)
9129
+ console.log(pc12.gray(`thinking: ${text58}`));
8949
9130
  continue;
8950
9131
  }
8951
9132
  if (type === "tool_call") {
8952
9133
  const name = asString3(part.name, asString3(part.tool, "tool"));
8953
9134
  console.log(pc12.yellow(`tool_call: ${name}`));
8954
9135
  const input = part.input ?? part.arguments ?? part.args;
8955
- if (input !== void 0) console.log(pc12.gray(stringifyUnknown2(input)));
9136
+ if (input !== void 0)
9137
+ console.log(pc12.gray(stringifyUnknown2(input)));
8956
9138
  continue;
8957
9139
  }
8958
9140
  if (type === "tool_result" || type === "tool_response") {
8959
9141
  const isError = part.is_error === true || asString3(part.status).toLowerCase() === "error";
8960
9142
  const contentText = asString3(part.output) || asString3(part.text) || asString3(part.result) || stringifyUnknown2(part.output ?? part.result ?? part.text ?? part.response);
8961
9143
  console.log((isError ? pc12.red : pc12.cyan)(`tool_result${isError ? " (error)" : ""}`));
8962
- if (contentText) console.log((isError ? pc12.red : pc12.gray)(contentText));
9144
+ if (contentText)
9145
+ console.log((isError ? pc12.red : pc12.gray)(contentText));
8963
9146
  }
8964
9147
  }
8965
9148
  }
@@ -8969,16 +9152,14 @@ function printUsage(parsed) {
8969
9152
  const source = usageMetadata ?? usage ?? {};
8970
9153
  const input = asNumber3(source.input_tokens, asNumber3(source.inputTokens, asNumber3(source.promptTokenCount)));
8971
9154
  const output = asNumber3(source.output_tokens, asNumber3(source.outputTokens, asNumber3(source.candidatesTokenCount)));
8972
- const cached = asNumber3(
8973
- source.cached_input_tokens,
8974
- asNumber3(source.cachedInputTokens, asNumber3(source.cachedContentTokenCount))
8975
- );
9155
+ const cached = asNumber3(source.cached_input_tokens, asNumber3(source.cachedInputTokens, asNumber3(source.cachedContentTokenCount)));
8976
9156
  const cost = asNumber3(parsed.total_cost_usd, asNumber3(parsed.cost_usd, asNumber3(parsed.cost)));
8977
9157
  console.log(pc12.blue(`tokens: in=${input} out=${output} cached=${cached} cost=$${cost.toFixed(6)}`));
8978
9158
  }
8979
9159
  function printGeminiStreamEvent(raw, _debug) {
8980
9160
  const line = raw.trim();
8981
- if (!line) return;
9161
+ if (!line)
9162
+ return;
8982
9163
  let parsed = null;
8983
9164
  try {
8984
9165
  parsed = JSON.parse(line);
@@ -8997,8 +9178,9 @@ function printGeminiStreamEvent(raw, _debug) {
8997
9178
  return;
8998
9179
  }
8999
9180
  if (subtype === "error") {
9000
- const text56 = errorText2(parsed.error ?? parsed.message ?? parsed.detail);
9001
- if (text56) console.log(pc12.red(`error: ${text56}`));
9181
+ const text58 = errorText2(parsed.error ?? parsed.message ?? parsed.detail);
9182
+ if (text58)
9183
+ console.log(pc12.red(`error: ${text58}`));
9002
9184
  return;
9003
9185
  }
9004
9186
  console.log(pc12.blue(`system: ${subtype || "event"}`));
@@ -9013,8 +9195,9 @@ function printGeminiStreamEvent(raw, _debug) {
9013
9195
  return;
9014
9196
  }
9015
9197
  if (type === "thinking") {
9016
- const text56 = asString3(parsed.text).trim() || asString3(asRecord3(parsed.delta)?.text).trim();
9017
- if (text56) console.log(pc12.gray(`thinking: ${text56}`));
9198
+ const text58 = asString3(parsed.text).trim() || asString3(asRecord3(parsed.delta)?.text).trim();
9199
+ if (text58)
9200
+ console.log(pc12.gray(`thinking: ${text58}`));
9018
9201
  return;
9019
9202
  }
9020
9203
  if (type === "tool_call") {
@@ -9050,24 +9233,26 @@ function printGeminiStreamEvent(raw, _debug) {
9050
9233
  return;
9051
9234
  }
9052
9235
  if (type === "error") {
9053
- const text56 = errorText2(parsed.error ?? parsed.message ?? parsed.detail);
9054
- if (text56) console.log(pc12.red(`error: ${text56}`));
9236
+ const text58 = errorText2(parsed.error ?? parsed.message ?? parsed.detail);
9237
+ if (text58)
9238
+ console.log(pc12.red(`error: ${text58}`));
9055
9239
  return;
9056
9240
  }
9057
9241
  console.log(line);
9058
9242
  }
9059
9243
 
9060
- // ../packages/adapters/opencode-local/src/cli/format-event.ts
9244
+ // ../../node_modules/@paperclipai/adapter-opencode-local/dist/cli/format-event.js
9061
9245
  import pc13 from "picocolors";
9062
- function safeJsonParse(text56) {
9246
+ function safeJsonParse(text58) {
9063
9247
  try {
9064
- return JSON.parse(text56);
9248
+ return JSON.parse(text58);
9065
9249
  } catch {
9066
9250
  return null;
9067
9251
  }
9068
9252
  }
9069
9253
  function asRecord4(value) {
9070
- if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
9254
+ if (typeof value !== "object" || value === null || Array.isArray(value))
9255
+ return null;
9071
9256
  return value;
9072
9257
  }
9073
9258
  function asString4(value, fallback = "") {
@@ -9077,12 +9262,15 @@ function asNumber4(value, fallback = 0) {
9077
9262
  return typeof value === "number" && Number.isFinite(value) ? value : fallback;
9078
9263
  }
9079
9264
  function errorText3(value) {
9080
- if (typeof value === "string") return value;
9265
+ if (typeof value === "string")
9266
+ return value;
9081
9267
  const rec = asRecord4(value);
9082
- if (!rec) return "";
9268
+ if (!rec)
9269
+ return "";
9083
9270
  const data = asRecord4(rec.data);
9084
9271
  const message = asString4(rec.message) || asString4(data?.message) || asString4(rec.name) || "";
9085
- if (message) return message;
9272
+ if (message)
9273
+ return message;
9086
9274
  try {
9087
9275
  return JSON.stringify(rec);
9088
9276
  } catch {
@@ -9091,7 +9279,8 @@ function errorText3(value) {
9091
9279
  }
9092
9280
  function printOpenCodeStreamEvent(raw, _debug) {
9093
9281
  const line = raw.trim();
9094
- if (!line) return;
9282
+ if (!line)
9283
+ return;
9095
9284
  const parsed = asRecord4(safeJsonParse(line));
9096
9285
  if (!parsed) {
9097
9286
  console.log(line);
@@ -9105,14 +9294,16 @@ function printOpenCodeStreamEvent(raw, _debug) {
9105
9294
  }
9106
9295
  if (type === "text") {
9107
9296
  const part = asRecord4(parsed.part);
9108
- const text56 = asString4(part?.text).trim();
9109
- if (text56) console.log(pc13.green(`assistant: ${text56}`));
9297
+ const text58 = asString4(part?.text).trim();
9298
+ if (text58)
9299
+ console.log(pc13.green(`assistant: ${text58}`));
9110
9300
  return;
9111
9301
  }
9112
9302
  if (type === "reasoning") {
9113
9303
  const part = asRecord4(parsed.part);
9114
- const text56 = asString4(part?.text).trim();
9115
- if (text56) console.log(pc13.gray(`thinking: ${text56}`));
9304
+ const text58 = asString4(part?.text).trim();
9305
+ if (text58)
9306
+ console.log(pc13.gray(`thinking: ${text58}`));
9116
9307
  return;
9117
9308
  }
9118
9309
  if (type === "tool_use") {
@@ -9128,13 +9319,15 @@ function printOpenCodeStreamEvent(raw, _debug) {
9128
9319
  const metaParts = [`status=${status}`];
9129
9320
  if (metadata) {
9130
9321
  for (const [key, value] of Object.entries(metadata)) {
9131
- if (value !== void 0 && value !== null) metaParts.push(`${key}=${value}`);
9322
+ if (value !== void 0 && value !== null)
9323
+ metaParts.push(`${key}=${value}`);
9132
9324
  }
9133
9325
  }
9134
9326
  console.log((isError ? pc13.red : pc13.gray)(`tool_result ${metaParts.join(" ")}`));
9135
9327
  }
9136
9328
  const output = (asString4(state?.output) || asString4(state?.error)).trim();
9137
- if (output) console.log((isError ? pc13.red : pc13.gray)(output));
9329
+ if (output)
9330
+ console.log((isError ? pc13.red : pc13.gray)(output));
9138
9331
  return;
9139
9332
  }
9140
9333
  if (type === "step_finish") {
@@ -9152,36 +9345,41 @@ function printOpenCodeStreamEvent(raw, _debug) {
9152
9345
  }
9153
9346
  if (type === "error") {
9154
9347
  const message = errorText3(parsed.error ?? parsed.message);
9155
- if (message) console.log(pc13.red(`error: ${message}`));
9348
+ if (message)
9349
+ console.log(pc13.red(`error: ${message}`));
9156
9350
  return;
9157
9351
  }
9158
9352
  console.log(line);
9159
9353
  }
9160
9354
 
9161
- // ../packages/adapters/pi-local/src/cli/format-event.ts
9355
+ // ../../node_modules/@paperclipai/adapter-pi-local/dist/cli/format-event.js
9162
9356
  import pc14 from "picocolors";
9163
- function safeJsonParse2(text56) {
9357
+ function safeJsonParse2(text58) {
9164
9358
  try {
9165
- return JSON.parse(text56);
9359
+ return JSON.parse(text58);
9166
9360
  } catch {
9167
9361
  return null;
9168
9362
  }
9169
9363
  }
9170
9364
  function asRecord5(value) {
9171
- if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
9365
+ if (typeof value !== "object" || value === null || Array.isArray(value))
9366
+ return null;
9172
9367
  return value;
9173
9368
  }
9174
9369
  function asString5(value, fallback = "") {
9175
9370
  return typeof value === "string" ? value : fallback;
9176
9371
  }
9177
9372
  function extractTextContent(content) {
9178
- if (typeof content === "string") return content;
9179
- if (!Array.isArray(content)) return "";
9373
+ if (typeof content === "string")
9374
+ return content;
9375
+ if (!Array.isArray(content))
9376
+ return "";
9180
9377
  return content.filter((c) => c.type === "text" && c.text).map((c) => c.text).join("");
9181
9378
  }
9182
9379
  function printPiStreamEvent(raw, _debug) {
9183
9380
  const line = raw.trim();
9184
- if (!line) return;
9381
+ if (!line)
9382
+ return;
9185
9383
  const parsed = asRecord5(safeJsonParse2(line));
9186
9384
  if (!parsed) {
9187
9385
  console.log(line);
@@ -9204,9 +9402,9 @@ function printPiStreamEvent(raw, _debug) {
9204
9402
  const message = asRecord5(parsed.message);
9205
9403
  if (message) {
9206
9404
  const content = message.content;
9207
- const text56 = extractTextContent(content);
9208
- if (text56) {
9209
- console.log(pc14.green(`assistant: ${text56}`));
9405
+ const text58 = extractTextContent(content);
9406
+ if (text58) {
9407
+ console.log(pc14.green(`assistant: ${text58}`));
9210
9408
  }
9211
9409
  }
9212
9410
  return;
@@ -9497,26 +9695,26 @@ var PaperclipApiClient = class {
9497
9695
  this.apiKey = opts.apiKey?.trim() || void 0;
9498
9696
  this.runId = opts.runId?.trim() || void 0;
9499
9697
  }
9500
- get(path19, opts) {
9501
- return this.request(path19, { method: "GET" }, opts);
9698
+ get(path24, opts) {
9699
+ return this.request(path24, { method: "GET" }, opts);
9502
9700
  }
9503
- post(path19, body, opts) {
9504
- return this.request(path19, {
9701
+ post(path24, body, opts) {
9702
+ return this.request(path24, {
9505
9703
  method: "POST",
9506
9704
  body: body === void 0 ? void 0 : JSON.stringify(body)
9507
9705
  }, opts);
9508
9706
  }
9509
- patch(path19, body, opts) {
9510
- return this.request(path19, {
9707
+ patch(path24, body, opts) {
9708
+ return this.request(path24, {
9511
9709
  method: "PATCH",
9512
9710
  body: body === void 0 ? void 0 : JSON.stringify(body)
9513
9711
  }, opts);
9514
9712
  }
9515
- delete(path19, opts) {
9516
- return this.request(path19, { method: "DELETE" }, opts);
9713
+ delete(path24, opts) {
9714
+ return this.request(path24, { method: "DELETE" }, opts);
9517
9715
  }
9518
- async request(path19, init, opts) {
9519
- const url = buildUrl(this.apiBase, path19);
9716
+ async request(path24, init, opts) {
9717
+ const url = buildUrl(this.apiBase, path24);
9520
9718
  const headers = {
9521
9719
  accept: "application/json",
9522
9720
  ...toStringRecord(init.headers)
@@ -9543,31 +9741,31 @@ var PaperclipApiClient = class {
9543
9741
  if (response.status === 204) {
9544
9742
  return null;
9545
9743
  }
9546
- const text56 = await response.text();
9547
- if (!text56.trim()) {
9744
+ const text58 = await response.text();
9745
+ if (!text58.trim()) {
9548
9746
  return null;
9549
9747
  }
9550
- return safeParseJson(text56);
9748
+ return safeParseJson(text58);
9551
9749
  }
9552
9750
  };
9553
- function buildUrl(apiBase, path19) {
9554
- const normalizedPath = path19.startsWith("/") ? path19 : `/${path19}`;
9751
+ function buildUrl(apiBase, path24) {
9752
+ const normalizedPath = path24.startsWith("/") ? path24 : `/${path24}`;
9555
9753
  const [pathname, query] = normalizedPath.split("?");
9556
9754
  const url = new URL2(apiBase);
9557
9755
  url.pathname = `${url.pathname.replace(/\/+$/, "")}${pathname}`;
9558
9756
  if (query) url.search = query;
9559
9757
  return url.toString();
9560
9758
  }
9561
- function safeParseJson(text56) {
9759
+ function safeParseJson(text58) {
9562
9760
  try {
9563
- return JSON.parse(text56);
9761
+ return JSON.parse(text58);
9564
9762
  } catch {
9565
- return text56;
9763
+ return text58;
9566
9764
  }
9567
9765
  }
9568
9766
  async function toApiError(response) {
9569
- const text56 = await response.text();
9570
- const parsed = safeParseJson(text56);
9767
+ const text58 = await response.text();
9768
+ const parsed = safeParseJson(text58);
9571
9769
  if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
9572
9770
  const body = parsed;
9573
9771
  const message = typeof body.error === "string" && body.error.trim() || typeof body.message === "string" && body.message.trim() || `Request failed with status ${response.status}`;
@@ -10459,8 +10657,8 @@ function registerIssueCommands(program2) {
10459
10657
  if (opts.assigneeAgentId) params.set("assigneeAgentId", opts.assigneeAgentId);
10460
10658
  if (opts.projectId) params.set("projectId", opts.projectId);
10461
10659
  const query = params.toString();
10462
- const path19 = `/api/companies/${ctx.companyId}/issues${query ? `?${query}` : ""}`;
10463
- const rows = await ctx.api.get(path19) ?? [];
10660
+ const path24 = `/api/companies/${ctx.companyId}/issues${query ? `?${query}` : ""}`;
10661
+ const rows = await ctx.api.get(path24) ?? [];
10464
10662
  const filtered = filterIssueRows(rows, opts.match);
10465
10663
  if (ctx.json) {
10466
10664
  printOutput(filtered, { json: true });
@@ -10616,8 +10814,8 @@ function filterIssueRows(rows, match) {
10616
10814
  if (!match?.trim()) return rows;
10617
10815
  const needle = match.trim().toLowerCase();
10618
10816
  return rows.filter((row) => {
10619
- const text56 = [row.identifier, row.title, row.description].filter((part) => Boolean(part)).join("\n").toLowerCase();
10620
- return text56.includes(needle);
10817
+ const text58 = [row.identifier, row.title, row.description].filter((part) => Boolean(part)).join("\n").toLowerCase();
10818
+ return text58.includes(needle);
10621
10819
  });
10622
10820
  }
10623
10821
 
@@ -11066,8 +11264,8 @@ function registerActivityCommands(program2) {
11066
11264
  if (opts.entityType) params.set("entityType", opts.entityType);
11067
11265
  if (opts.entityId) params.set("entityId", opts.entityId);
11068
11266
  const query = params.toString();
11069
- const path19 = `/api/companies/${ctx.companyId}/activity${query ? `?${query}` : ""}`;
11070
- const rows = await ctx.api.get(path19) ?? [];
11267
+ const path24 = `/api/companies/${ctx.companyId}/activity${query ? `?${query}` : ""}`;
11268
+ const rows = await ctx.api.get(path24) ?? [];
11071
11269
  if (ctx.json) {
11072
11270
  printOutput(rows, { json: true });
11073
11271
  return;
@@ -12073,6 +12271,15 @@ async function worktreeMakeCommand(nameArg, opts) {
12073
12271
  } finally {
12074
12272
  process.chdir(originalCwd);
12075
12273
  }
12274
+ const bootstrapScript = path17.resolve(sourceCwd, "scripts/worktree-bootstrap.mjs");
12275
+ if (existsSync2(bootstrapScript)) {
12276
+ p15.log.message(pc21.dim(`Running worktree bootstrap in ${targetPath}...`));
12277
+ try {
12278
+ execFileSync("node", [bootstrapScript], { cwd: targetPath, stdio: "inherit" });
12279
+ } catch (error) {
12280
+ p15.log.warning(`Bootstrap failed: ${extractExecSyncErrorMessage(error) ?? String(error)}`);
12281
+ }
12282
+ }
12076
12283
  }
12077
12284
  function parseGitWorktreeList(cwd) {
12078
12285
  const raw = execFileSync("git", ["worktree", "list", "--porcelain"], {
@@ -12294,16 +12501,16 @@ function resolvePackageArg(packageArg, isLocal) {
12294
12501
  }
12295
12502
  return path18.resolve(process.cwd(), packageArg);
12296
12503
  }
12297
- function formatPlugin(p16) {
12298
- const statusColor = p16.status === "ready" ? pc22.green(p16.status) : p16.status === "error" ? pc22.red(p16.status) : p16.status === "disabled" ? pc22.dim(p16.status) : pc22.yellow(p16.status);
12504
+ function formatPlugin(p19) {
12505
+ const statusColor = p19.status === "ready" ? pc22.green(p19.status) : p19.status === "error" ? pc22.red(p19.status) : p19.status === "disabled" ? pc22.dim(p19.status) : pc22.yellow(p19.status);
12299
12506
  const parts = [
12300
- `key=${pc22.bold(p16.pluginKey)}`,
12507
+ `key=${pc22.bold(p19.pluginKey)}`,
12301
12508
  `status=${statusColor}`,
12302
- `version=${p16.version}`,
12303
- `id=${pc22.dim(p16.id)}`
12509
+ `version=${p19.version}`,
12510
+ `id=${pc22.dim(p19.id)}`
12304
12511
  ];
12305
- if (p16.lastError) {
12306
- parts.push(`error=${pc22.red(p16.lastError.slice(0, 80))}`);
12512
+ if (p19.lastError) {
12513
+ parts.push(`error=${pc22.red(p19.lastError.slice(0, 80))}`);
12307
12514
  }
12308
12515
  return parts.join(" ");
12309
12516
  }
@@ -12324,8 +12531,8 @@ function registerPluginCommands(program2) {
12324
12531
  console.log(pc22.dim("No plugins installed."));
12325
12532
  return;
12326
12533
  }
12327
- for (const p16 of rows) {
12328
- console.log(formatPlugin(p16));
12534
+ for (const p19 of rows) {
12535
+ console.log(formatPlugin(p19));
12329
12536
  }
12330
12537
  } catch (err) {
12331
12538
  handleCommandError(err);
@@ -12489,48 +12696,482 @@ ${result.lastError}`);
12489
12696
  );
12490
12697
  }
12491
12698
 
12492
- function resolveKitAssetRootDist(kitId) {
12493
- const moduleDir = path17.dirname(fileURLToPath2(import.meta.url));
12494
- const assetRoot = path17.resolve(moduleDir, "../assets/worker-kits", kitId);
12495
- if (!existsSync2(assetRoot)) {
12496
- throw new Error(`Bundled worker kit assets not found for ${kitId}: ${assetRoot}`);
12699
+ // src/commands/kit.ts
12700
+ import path20 from "node:path";
12701
+ import { pathToFileURL as pathToFileURL2 } from "node:url";
12702
+ import * as p16 from "@clack/prompts";
12703
+ import pc23 from "picocolors";
12704
+
12705
+ // src/kits/service.ts
12706
+ init_home();
12707
+ import fs14 from "node:fs";
12708
+ import path19 from "node:path";
12709
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
12710
+
12711
+ // src/kits/catalog.ts
12712
+ var BUNDLED_KIT_CATALOG = [
12713
+ {
12714
+ id: "creative-strategist-v1",
12715
+ packageDirName: "creative-strategist-v1",
12716
+ defaultBundleId: "creative-strategist-v1",
12717
+ type: "worker",
12718
+ executionMode: "export",
12719
+ activationModes: ["export"],
12720
+ family: "workflow"
12721
+ },
12722
+ {
12723
+ id: "growthub-email-marketing-v1",
12724
+ packageDirName: "growthub-email-marketing-v1",
12725
+ defaultBundleId: "growthub-email-marketing-v1",
12726
+ type: "worker",
12727
+ executionMode: "export",
12728
+ activationModes: ["export"],
12729
+ family: "operator"
12730
+ },
12731
+ {
12732
+ id: "growthub-open-higgsfield-studio-v1",
12733
+ packageDirName: "growthub-open-higgsfield-studio-v1",
12734
+ defaultBundleId: "growthub-open-higgsfield-studio-v1",
12735
+ type: "worker",
12736
+ executionMode: "export",
12737
+ activationModes: ["export"],
12738
+ family: "studio"
12497
12739
  }
12498
- return assetRoot;
12740
+ ];
12741
+
12742
+ // src/kits/contract.ts
12743
+ function isManifestV2(manifest) {
12744
+ return manifest.schemaVersion === 2;
12745
+ }
12746
+ function isBundleManifestV2(manifest) {
12747
+ return manifest.schemaVersion === 2;
12748
+ }
12749
+ function normalizeManifest(manifest) {
12750
+ if (isManifestV2(manifest)) return manifest;
12751
+ return {
12752
+ schemaVersion: 2,
12753
+ kit: {
12754
+ ...manifest.kit,
12755
+ type: "worker"
12756
+ },
12757
+ entrypoint: manifest.entrypoint,
12758
+ workerIds: manifest.workerIds,
12759
+ agentContractPath: manifest.agentContractPath,
12760
+ brandTemplatePath: manifest.brandTemplatePath,
12761
+ publicExampleBrandPaths: manifest.publicExampleBrandPaths,
12762
+ frozenAssetPaths: manifest.frozenAssetPaths,
12763
+ outputStandard: manifest.outputStandard,
12764
+ bundles: manifest.bundles,
12765
+ executionMode: "export",
12766
+ activationModes: ["export"],
12767
+ compatibility: {},
12768
+ provenance: manifest.kit.sourceRepo ? { sourceRepo: manifest.kit.sourceRepo } : void 0
12769
+ };
12499
12770
  }
12500
- function resolveKitOutputRootDist(outDir) {
12501
- if (typeof outDir === "string" && outDir.trim().length > 0) {
12502
- return path17.resolve(expandHomePrefix(outDir.trim()));
12771
+ function normalizeBundleManifest(manifest) {
12772
+ if (isBundleManifestV2(manifest)) return manifest;
12773
+ return {
12774
+ schemaVersion: 2,
12775
+ bundle: manifest.bundle,
12776
+ briefType: manifest.briefType,
12777
+ publicExampleBrandPaths: manifest.publicExampleBrandPaths,
12778
+ requiredFrozenAssets: manifest.requiredFrozenAssets,
12779
+ optionalPresets: manifest.optionalPresets,
12780
+ export: manifest.export,
12781
+ activationModes: ["export"]
12782
+ };
12783
+ }
12784
+ var SUPPORTED_SCHEMA_VERSIONS = [1, 2];
12785
+ var KIT_CAPABILITY_TYPES = [
12786
+ "worker",
12787
+ "workflow",
12788
+ "output",
12789
+ "ui"
12790
+ ];
12791
+ var KIT_ACTIVATION_MODES = [
12792
+ "export",
12793
+ "install",
12794
+ "mount",
12795
+ "run"
12796
+ ];
12797
+
12798
+ // src/kits/service.ts
12799
+ var ZIP_TIMESTAMP = /* @__PURE__ */ new Date("2026-04-09T00:00:00.000Z");
12800
+ function resolveBundledKitAssetsRoot() {
12801
+ const moduleDir = path19.dirname(fileURLToPath4(import.meta.url));
12802
+ const candidates = [
12803
+ path19.resolve(moduleDir, "../../assets/worker-kits"),
12804
+ path19.resolve(moduleDir, "../assets/worker-kits")
12805
+ ];
12806
+ for (const candidate of candidates) {
12807
+ if (fs14.existsSync(candidate)) return candidate;
12503
12808
  }
12504
- return path17.resolve(resolvePaperclipHomeDir(), "kits", "exports");
12809
+ throw new Error("Could not locate bundled worker kit assets.");
12505
12810
  }
12506
- function readJsonDist(filePath) {
12507
- return JSON.parse(readFileSync(filePath, "utf8"));
12811
+ function resolveRequestedOutputRoot(outDir) {
12812
+ if (outDir?.trim()) {
12813
+ return path19.resolve(expandHomePrefix(outDir.trim()));
12814
+ }
12815
+ return path19.resolve(resolvePaperclipHomeDir(), "kits", "exports");
12508
12816
  }
12509
- function listFilesRecursiveDist(rootDir, currentDir = rootDir) {
12510
- const entries = [];
12511
- for (const entry of readdirSync2(currentDir, { withFileTypes: true })) {
12512
- const fullPath = path17.join(currentDir, entry.name);
12513
- if (entry.isDirectory()) {
12514
- entries.push(...listFilesRecursiveDist(rootDir, fullPath));
12515
- continue;
12817
+ function readJsonFile(filePath) {
12818
+ return JSON.parse(fs14.readFileSync(filePath, "utf8"));
12819
+ }
12820
+ function assertRelativePathExists(assetRoot, relativePath, label) {
12821
+ const fullPath = path19.resolve(assetRoot, relativePath);
12822
+ if (!fs14.existsSync(fullPath)) {
12823
+ throw new Error(`${label} is missing required path: ${relativePath}`);
12824
+ }
12825
+ }
12826
+ function listRelativeFiles(rootDir) {
12827
+ const files = [];
12828
+ const walk = (currentDir) => {
12829
+ for (const entry of fs14.readdirSync(currentDir, { withFileTypes: true })) {
12830
+ const fullPath = path19.join(currentDir, entry.name);
12831
+ if (entry.isDirectory()) {
12832
+ walk(fullPath);
12833
+ continue;
12834
+ }
12835
+ files.push(path19.relative(rootDir, fullPath).split(path19.sep).join("/"));
12516
12836
  }
12517
- entries.push(path17.relative(rootDir, fullPath).split(path17.sep).join("/"));
12837
+ };
12838
+ walk(rootDir);
12839
+ return files.sort();
12840
+ }
12841
+ function parseManifest(assetRoot) {
12842
+ const raw = readJsonFile(path19.resolve(assetRoot, "kit.json"));
12843
+ if (!SUPPORTED_SCHEMA_VERSIONS.includes(raw.schemaVersion)) {
12844
+ throw new Error(`Unsupported kit schema version for ${assetRoot}: ${raw.schemaVersion}`);
12518
12845
  }
12519
- return entries.sort();
12846
+ return normalizeManifest(raw);
12520
12847
  }
12521
- function copyDirRecursiveDist(sourceDir, targetDir) {
12522
- mkdirSync2(targetDir, { recursive: true });
12523
- for (const entry of readdirSync2(sourceDir, { withFileTypes: true })) {
12524
- const sourcePath = path17.join(sourceDir, entry.name);
12525
- const targetPath = path17.join(targetDir, entry.name);
12526
- if (entry.isDirectory()) {
12527
- copyDirRecursiveDist(sourcePath, targetPath);
12528
- continue;
12848
+ function parseBundleManifest(assetRoot, manifest, bundleId) {
12849
+ const bundleRef = manifest.bundles.find((item) => item.id === bundleId);
12850
+ if (!bundleRef) {
12851
+ throw new Error(`Kit ${manifest.kit.id} does not declare bundle ${bundleId}.`);
12852
+ }
12853
+ const raw = readJsonFile(path19.resolve(assetRoot, bundleRef.path));
12854
+ if (!SUPPORTED_SCHEMA_VERSIONS.includes(raw.schemaVersion)) {
12855
+ throw new Error(
12856
+ `Unsupported bundle schema version for ${bundleRef.path}: ${raw.schemaVersion}`
12857
+ );
12858
+ }
12859
+ return normalizeBundleManifest(raw);
12860
+ }
12861
+ function validateBundledKit(resolved) {
12862
+ const { assetRoot, manifest, bundleManifest } = resolved;
12863
+ if (manifest.kit.id !== resolved.catalogEntry.id) {
12864
+ throw new Error(
12865
+ `Bundled catalog mismatch: expected ${resolved.catalogEntry.id}, got ${manifest.kit.id}.`
12866
+ );
12867
+ }
12868
+ if (bundleManifest.bundle.kitId !== manifest.kit.id) {
12869
+ throw new Error(
12870
+ `Bundle ${bundleManifest.bundle.id} points at ${bundleManifest.bundle.kitId}, expected ${manifest.kit.id}.`
12871
+ );
12872
+ }
12873
+ if (bundleManifest.bundle.workerId !== manifest.entrypoint.workerId) {
12874
+ throw new Error(
12875
+ `Bundle ${bundleManifest.bundle.id} worker mismatch: ${bundleManifest.bundle.workerId} vs ${manifest.entrypoint.workerId}.`
12876
+ );
12877
+ }
12878
+ assertRelativePathExists(assetRoot, manifest.entrypoint.path, "Kit manifest");
12879
+ assertRelativePathExists(assetRoot, manifest.agentContractPath, "Kit manifest");
12880
+ assertRelativePathExists(assetRoot, manifest.brandTemplatePath, "Kit manifest");
12881
+ for (const bundle of manifest.bundles) {
12882
+ assertRelativePathExists(assetRoot, bundle.path, "Kit manifest bundle");
12883
+ }
12884
+ for (const relativePath of manifest.frozenAssetPaths) {
12885
+ assertRelativePathExists(assetRoot, relativePath, "Kit manifest");
12886
+ }
12887
+ for (const requiredPath of manifest.outputStandard.requiredPaths) {
12888
+ assertRelativePathExists(assetRoot, requiredPath, "Output standard");
12889
+ }
12890
+ for (const relativePath of bundleManifest.requiredFrozenAssets) {
12891
+ assertRelativePathExists(assetRoot, relativePath, "Bundle manifest");
12892
+ }
12893
+ const kitPublicBrands = new Set(manifest.publicExampleBrandPaths ?? []);
12894
+ const bundlePublicBrands = new Set(bundleManifest.publicExampleBrandPaths ?? []);
12895
+ for (const brandPath of kitPublicBrands) {
12896
+ if (!bundlePublicBrands.has(brandPath)) {
12897
+ throw new Error(`Bundle ${bundleManifest.bundle.id} is missing declared public brand ${brandPath}.`);
12529
12898
  }
12530
- copyFileSync(sourcePath, targetPath);
12899
+ }
12900
+ const bundledFiles = listRelativeFiles(assetRoot);
12901
+ const brandKitFiles = bundledFiles.filter((filePath) => filePath.startsWith("brands/") && filePath.endsWith("/brand-kit.md"));
12902
+ const allowedBrandPaths = /* @__PURE__ */ new Set([
12903
+ manifest.brandTemplatePath,
12904
+ ...manifest.publicExampleBrandPaths ?? []
12905
+ ]);
12906
+ const disallowedBrandFiles = brandKitFiles.filter((filePath) => !allowedBrandPaths.has(filePath));
12907
+ if (disallowedBrandFiles.length > 0) {
12908
+ throw new Error(
12909
+ `Bundled kit ${manifest.kit.id} includes non-public brand kits: ${disallowedBrandFiles.join(", ")}`
12910
+ );
12531
12911
  }
12532
12912
  }
12533
- function crc32Dist(buffer) {
12913
+ function validateKitDirectory(kitPath) {
12914
+ const errors = [];
12915
+ const warnings = [];
12916
+ let schemaVersion = 0;
12917
+ let kitId = "<unknown>";
12918
+ const kitJsonPath = path19.resolve(kitPath, "kit.json");
12919
+ if (!fs14.existsSync(kitJsonPath)) {
12920
+ errors.push({ field: "kit.json", message: "kit.json not found in kit directory" });
12921
+ return { valid: false, schemaVersion, kitId, errors, warnings };
12922
+ }
12923
+ let raw;
12924
+ try {
12925
+ raw = JSON.parse(fs14.readFileSync(kitJsonPath, "utf8"));
12926
+ } catch {
12927
+ errors.push({ field: "kit.json", message: "kit.json is not valid JSON" });
12928
+ return { valid: false, schemaVersion, kitId, errors, warnings };
12929
+ }
12930
+ schemaVersion = typeof raw.schemaVersion === "number" ? raw.schemaVersion : 0;
12931
+ if (!SUPPORTED_SCHEMA_VERSIONS.includes(schemaVersion)) {
12932
+ errors.push({
12933
+ field: "schemaVersion",
12934
+ message: `Unsupported schema version ${schemaVersion}. Supported: ${SUPPORTED_SCHEMA_VERSIONS.join(", ")}`
12935
+ });
12936
+ return { valid: false, schemaVersion, kitId, errors, warnings };
12937
+ }
12938
+ const kitBlock = raw.kit;
12939
+ if (!kitBlock || typeof kitBlock !== "object") {
12940
+ errors.push({ field: "kit", message: "Missing required 'kit' block" });
12941
+ return { valid: false, schemaVersion, kitId, errors, warnings };
12942
+ }
12943
+ kitId = typeof kitBlock.id === "string" ? kitBlock.id : "<unknown>";
12944
+ for (const field of ["id", "version", "name", "description"]) {
12945
+ if (typeof kitBlock[field] !== "string" || kitBlock[field].trim() === "") {
12946
+ errors.push({ field: `kit.${field}`, message: `Missing or empty required field 'kit.${field}'` });
12947
+ }
12948
+ }
12949
+ if (schemaVersion === 2) {
12950
+ const kitType = kitBlock.type;
12951
+ if (!kitType || !KIT_CAPABILITY_TYPES.includes(kitType)) {
12952
+ errors.push({
12953
+ field: "kit.type",
12954
+ message: `Invalid or missing kit.type. Expected one of: ${KIT_CAPABILITY_TYPES.join(", ")}`
12955
+ });
12956
+ }
12957
+ const execMode = raw.executionMode;
12958
+ if (!execMode) {
12959
+ errors.push({ field: "executionMode", message: "Missing required field 'executionMode'" });
12960
+ } else if (!KIT_ACTIVATION_MODES.includes(execMode)) {
12961
+ errors.push({
12962
+ field: "executionMode",
12963
+ message: `Invalid executionMode '${execMode}'. Expected one of: ${KIT_ACTIVATION_MODES.join(", ")}`
12964
+ });
12965
+ }
12966
+ const activationModes = raw.activationModes;
12967
+ if (!Array.isArray(activationModes) || activationModes.length === 0) {
12968
+ errors.push({ field: "activationModes", message: "Missing or empty 'activationModes' array" });
12969
+ } else {
12970
+ for (const mode of activationModes) {
12971
+ if (!KIT_ACTIVATION_MODES.includes(mode)) {
12972
+ errors.push({
12973
+ field: "activationModes",
12974
+ message: `Invalid activation mode '${mode}'. Expected one of: ${KIT_ACTIVATION_MODES.join(", ")}`
12975
+ });
12976
+ }
12977
+ }
12978
+ }
12979
+ } else {
12980
+ warnings.push({ field: "schemaVersion", message: "Kit uses schema v1. Consider upgrading to v2 for capability metadata." });
12981
+ }
12982
+ const entrypoint = raw.entrypoint;
12983
+ if (!entrypoint || typeof entrypoint !== "object") {
12984
+ errors.push({ field: "entrypoint", message: "Missing required 'entrypoint' block" });
12985
+ } else {
12986
+ if (typeof entrypoint.workerId !== "string") {
12987
+ errors.push({ field: "entrypoint.workerId", message: "Missing required field 'entrypoint.workerId'" });
12988
+ }
12989
+ if (typeof entrypoint.path !== "string") {
12990
+ errors.push({ field: "entrypoint.path", message: "Missing required field 'entrypoint.path'" });
12991
+ } else {
12992
+ const fullPath = path19.resolve(kitPath, entrypoint.path);
12993
+ if (!fs14.existsSync(fullPath)) {
12994
+ errors.push({ field: "entrypoint.path", message: `Entrypoint file not found: ${entrypoint.path}` });
12995
+ }
12996
+ }
12997
+ }
12998
+ if (typeof raw.agentContractPath !== "string") {
12999
+ errors.push({ field: "agentContractPath", message: "Missing required field 'agentContractPath'" });
13000
+ } else {
13001
+ const fullPath = path19.resolve(kitPath, raw.agentContractPath);
13002
+ if (!fs14.existsSync(fullPath)) {
13003
+ errors.push({ field: "agentContractPath", message: `Agent contract not found: ${raw.agentContractPath}` });
13004
+ }
13005
+ }
13006
+ if (typeof raw.brandTemplatePath !== "string") {
13007
+ errors.push({ field: "brandTemplatePath", message: "Missing required field 'brandTemplatePath'" });
13008
+ } else {
13009
+ const fullPath = path19.resolve(kitPath, raw.brandTemplatePath);
13010
+ if (!fs14.existsSync(fullPath)) {
13011
+ errors.push({ field: "brandTemplatePath", message: `Brand template not found: ${raw.brandTemplatePath}` });
13012
+ }
13013
+ }
13014
+ const frozenAssets = raw.frozenAssetPaths;
13015
+ if (!Array.isArray(frozenAssets)) {
13016
+ errors.push({ field: "frozenAssetPaths", message: "Missing required 'frozenAssetPaths' array" });
13017
+ } else {
13018
+ for (const assetPath of frozenAssets) {
13019
+ if (typeof assetPath !== "string") continue;
13020
+ const fullPath = path19.resolve(kitPath, assetPath);
13021
+ if (!fs14.existsSync(fullPath)) {
13022
+ errors.push({ field: "frozenAssetPaths", message: `Frozen asset not found: ${assetPath}` });
13023
+ }
13024
+ }
13025
+ }
13026
+ const outputStandard = raw.outputStandard;
13027
+ if (!outputStandard || typeof outputStandard !== "object") {
13028
+ errors.push({ field: "outputStandard", message: "Missing required 'outputStandard' block" });
13029
+ } else {
13030
+ if (typeof outputStandard.type !== "string") {
13031
+ errors.push({ field: "outputStandard.type", message: "Missing required field 'outputStandard.type'" });
13032
+ }
13033
+ const requiredPaths = outputStandard.requiredPaths;
13034
+ if (!Array.isArray(requiredPaths)) {
13035
+ errors.push({ field: "outputStandard.requiredPaths", message: "Missing required 'outputStandard.requiredPaths' array" });
13036
+ } else {
13037
+ for (const reqPath of requiredPaths) {
13038
+ if (typeof reqPath !== "string") continue;
13039
+ const fullPath = path19.resolve(kitPath, reqPath);
13040
+ if (!fs14.existsSync(fullPath)) {
13041
+ errors.push({ field: "outputStandard.requiredPaths", message: `Required output path not found: ${reqPath}` });
13042
+ }
13043
+ }
13044
+ }
13045
+ }
13046
+ const bundles = raw.bundles;
13047
+ if (!Array.isArray(bundles) || bundles.length === 0) {
13048
+ errors.push({ field: "bundles", message: "Missing or empty 'bundles' array" });
13049
+ } else {
13050
+ for (const bundleRef of bundles) {
13051
+ const ref = bundleRef;
13052
+ if (typeof ref.path !== "string") {
13053
+ errors.push({ field: "bundles[].path", message: "Bundle ref missing 'path' field" });
13054
+ continue;
13055
+ }
13056
+ const bundlePath = path19.resolve(kitPath, ref.path);
13057
+ if (!fs14.existsSync(bundlePath)) {
13058
+ errors.push({ field: "bundles[].path", message: `Bundle manifest not found: ${ref.path}` });
13059
+ continue;
13060
+ }
13061
+ try {
13062
+ const bundleRaw = JSON.parse(fs14.readFileSync(bundlePath, "utf8"));
13063
+ const bundleBlock = bundleRaw.bundle;
13064
+ if (!bundleBlock || typeof bundleBlock !== "object") {
13065
+ errors.push({ field: `bundle(${ref.id})`, message: "Bundle manifest missing 'bundle' block" });
13066
+ } else {
13067
+ if (bundleBlock.kitId !== kitId) {
13068
+ errors.push({
13069
+ field: `bundle(${ref.id}).kitId`,
13070
+ message: `Bundle kitId '${bundleBlock.kitId}' does not match kit id '${kitId}'`
13071
+ });
13072
+ }
13073
+ }
13074
+ if (!bundleRaw.export || typeof bundleRaw.export !== "object") {
13075
+ errors.push({ field: `bundle(${ref.id}).export`, message: "Bundle manifest missing 'export' block" });
13076
+ }
13077
+ } catch {
13078
+ errors.push({ field: `bundle(${ref.id})`, message: `Bundle manifest at ${ref.path} is not valid JSON` });
13079
+ }
13080
+ }
13081
+ }
13082
+ return {
13083
+ valid: errors.length === 0,
13084
+ schemaVersion,
13085
+ kitId,
13086
+ errors,
13087
+ warnings
13088
+ };
13089
+ }
13090
+ function loadResolvedBundledKit(assetRoot, catalogEntry) {
13091
+ const manifest = parseManifest(assetRoot);
13092
+ const bundleManifest = parseBundleManifest(assetRoot, manifest, catalogEntry.defaultBundleId);
13093
+ const resolved = { catalogEntry, assetRoot, manifest, bundleManifest };
13094
+ validateBundledKit(resolved);
13095
+ return resolved;
13096
+ }
13097
+ function fuzzyResolveKitId(input) {
13098
+ const needle = input.toLowerCase().trim();
13099
+ const exact = BUNDLED_KIT_CATALOG.find((e) => e.id === needle);
13100
+ if (exact) return exact.id;
13101
+ const suffix = BUNDLED_KIT_CATALOG.find((e) => e.id.endsWith(needle));
13102
+ if (suffix) return suffix.id;
13103
+ const contains = BUNDLED_KIT_CATALOG.find((e) => e.id.includes(needle));
13104
+ if (contains) return contains.id;
13105
+ const tokens = needle.split(/[-\s]+/).filter((t) => t.length > 2);
13106
+ for (const token of tokens) {
13107
+ const tokenMatch = BUNDLED_KIT_CATALOG.find((e) => e.id.includes(token));
13108
+ if (tokenMatch) return tokenMatch.id;
13109
+ }
13110
+ return null;
13111
+ }
13112
+ function resolveBundledKit(kitId) {
13113
+ const resolvedId = fuzzyResolveKitId(kitId);
13114
+ if (!resolvedId) {
13115
+ const available = BUNDLED_KIT_CATALOG.map((e) => e.id).join(", ");
13116
+ throw new Error(
13117
+ `Unknown kit '${kitId}'. Run 'growthub kit list' to browse available kits.
13118
+ Available: ${available}`
13119
+ );
13120
+ }
13121
+ const catalogEntry = BUNDLED_KIT_CATALOG.find((e) => e.id === resolvedId);
13122
+ const assetRoot = path19.resolve(resolveBundledKitAssetsRoot(), catalogEntry.packageDirName);
13123
+ return loadResolvedBundledKit(assetRoot, catalogEntry);
13124
+ }
13125
+ function toListItem(resolved) {
13126
+ return {
13127
+ id: resolved.manifest.kit.id,
13128
+ version: resolved.manifest.kit.version,
13129
+ name: resolved.manifest.kit.name,
13130
+ description: resolved.manifest.kit.description,
13131
+ type: resolved.manifest.kit.type,
13132
+ family: resolved.catalogEntry.family,
13133
+ executionMode: resolved.manifest.executionMode,
13134
+ activationModes: resolved.manifest.activationModes,
13135
+ bundleId: resolved.bundleManifest.bundle.id,
13136
+ bundleVersion: resolved.bundleManifest.bundle.version,
13137
+ briefType: resolved.bundleManifest.briefType
13138
+ };
13139
+ }
13140
+ function resolveOutputPaths(resolved, outDir) {
13141
+ const outputRoot = resolveRequestedOutputRoot(outDir);
13142
+ const folderPath = path19.resolve(outputRoot, resolved.bundleManifest.export.folderName);
13143
+ const zipPath = path19.resolve(outputRoot, resolved.bundleManifest.export.zipFileName);
13144
+ return { outputRoot, folderPath, zipPath };
13145
+ }
13146
+ function listBundledKits() {
13147
+ return BUNDLED_KIT_CATALOG.map((entry) => toListItem(resolveBundledKit(entry.id)));
13148
+ }
13149
+ function inspectBundledKit(kitId, outDir) {
13150
+ const resolved = resolveBundledKit(kitId);
13151
+ const outputPaths = resolveOutputPaths(resolved, outDir);
13152
+ return {
13153
+ ...toListItem(resolved),
13154
+ entrypointPath: resolved.manifest.entrypoint.path,
13155
+ agentContractPath: resolved.manifest.agentContractPath,
13156
+ brandTemplatePath: resolved.manifest.brandTemplatePath,
13157
+ publicExampleBrandPaths: resolved.manifest.publicExampleBrandPaths ?? [],
13158
+ frozenAssetCount: resolved.manifest.frozenAssetPaths.length,
13159
+ requiredFrozenAssetCount: resolved.bundleManifest.requiredFrozenAssets.length,
13160
+ outputRoot: outputPaths.outputRoot,
13161
+ exportFolderName: resolved.bundleManifest.export.folderName,
13162
+ exportFolderPath: outputPaths.folderPath,
13163
+ exportZipName: resolved.bundleManifest.export.zipFileName,
13164
+ exportZipPath: outputPaths.zipPath,
13165
+ requiredPaths: resolved.manifest.outputStandard.requiredPaths,
13166
+ compatibility: resolved.manifest.compatibility,
13167
+ schemaVersion: resolved.manifest.schemaVersion
13168
+ };
13169
+ }
13170
+ function resolveKitPath(kitId, outDir) {
13171
+ const resolved = resolveBundledKit(kitId);
13172
+ return resolveOutputPaths(resolved, outDir).folderPath;
13173
+ }
13174
+ function crc32(buffer) {
12534
13175
  let crc = 4294967295;
12535
13176
  for (const byte of buffer) {
12536
13177
  crc ^= byte;
@@ -12540,27 +13181,27 @@ function crc32Dist(buffer) {
12540
13181
  }
12541
13182
  return (crc ^ 4294967295) >>> 0;
12542
13183
  }
12543
- function toDosDateTimeDist(date) {
12544
- const year = Math.max(date.getUTCFullYear(), 1980);
12545
- const month = date.getUTCMonth() + 1;
12546
- const day = date.getUTCDate();
12547
- const hours = date.getUTCHours();
12548
- const minutes = date.getUTCMinutes();
12549
- const seconds = Math.floor(date.getUTCSeconds() / 2);
13184
+ function toDosTimeParts(date2) {
13185
+ const year = Math.max(date2.getUTCFullYear(), 1980);
13186
+ const month = date2.getUTCMonth() + 1;
13187
+ const day = date2.getUTCDate();
13188
+ const hours = date2.getUTCHours();
13189
+ const minutes = date2.getUTCMinutes();
13190
+ const seconds = Math.floor(date2.getUTCSeconds() / 2);
12550
13191
  return {
12551
13192
  dosTime: hours << 11 | minutes << 5 | seconds,
12552
13193
  dosDate: year - 1980 << 9 | month << 5 | day
12553
13194
  };
12554
13195
  }
12555
- function buildStoredZipDist(entries) {
13196
+ function buildStoredZip(entries) {
12556
13197
  const parts = [];
12557
- const central = [];
13198
+ const centralDirectoryParts = [];
12558
13199
  let offset = 0;
12559
- const { dosTime, dosDate } = toDosDateTimeDist(new Date("2026-04-09T00:00:00.000Z"));
13200
+ const { dosTime, dosDate } = toDosTimeParts(ZIP_TIMESTAMP);
12560
13201
  for (const entry of entries) {
12561
13202
  const nameBuffer = Buffer.from(entry.name, "utf8");
12562
13203
  const data = entry.data;
12563
- const checksum = crc32Dist(data);
13204
+ const checksum = crc32(data);
12564
13205
  const localHeader = Buffer.alloc(30 + nameBuffer.length);
12565
13206
  localHeader.writeUInt32LE(67324752, 0);
12566
13207
  localHeader.writeUInt16LE(20, 4);
@@ -12594,10 +13235,10 @@ function buildStoredZipDist(entries) {
12594
13235
  centralHeader.writeUInt32LE(0, 38);
12595
13236
  centralHeader.writeUInt32LE(offset, 42);
12596
13237
  nameBuffer.copy(centralHeader, 46);
12597
- central.push(centralHeader);
13238
+ centralDirectoryParts.push(centralHeader);
12598
13239
  offset += localHeader.length + data.length;
12599
13240
  }
12600
- const centralDirectory = Buffer.concat(central);
13241
+ const centralDirectory = Buffer.concat(centralDirectoryParts);
12601
13242
  const endRecord = Buffer.alloc(22);
12602
13243
  endRecord.writeUInt32LE(101010256, 0);
12603
13244
  endRecord.writeUInt16LE(0, 4);
@@ -12609,106 +13250,1247 @@ function buildStoredZipDist(entries) {
12609
13250
  endRecord.writeUInt16LE(0, 20);
12610
13251
  return Buffer.concat([...parts, centralDirectory, endRecord]);
12611
13252
  }
12612
- function validateKitAssetRootDist(assetRoot, manifest, bundleManifest) {
12613
- const requiredPaths = [
12614
- "kit.json",
12615
- ...manifest.frozenAssetPaths,
12616
- ...manifest.outputStandard.requiredPaths,
12617
- ...bundleManifest.requiredFrozenAssets
12618
- ];
12619
- for (const relativePath of requiredPaths) {
12620
- const fullPath = path17.resolve(assetRoot, relativePath);
12621
- if (!existsSync2(fullPath)) {
12622
- throw new Error(`Bundled worker kit validation failed. Missing required path: ${relativePath}`);
12623
- }
12624
- }
13253
+ function reportProgress(onProgress, progress) {
13254
+ onProgress?.(progress);
13255
+ }
13256
+ function copyDirectoryWithProgress(sourceRoot, targetRoot, onProgress) {
13257
+ const files = listRelativeFiles(sourceRoot);
13258
+ const total = Math.max(files.length, 1);
13259
+ fs14.mkdirSync(targetRoot, { recursive: true });
13260
+ reportProgress(onProgress, {
13261
+ phase: "copying",
13262
+ completed: 0,
13263
+ total,
13264
+ percent: 10,
13265
+ detail: "Preparing files"
13266
+ });
13267
+ files.forEach((relativePath, index51) => {
13268
+ const sourcePath = path19.resolve(sourceRoot, relativePath);
13269
+ const targetPath = path19.resolve(targetRoot, relativePath);
13270
+ fs14.mkdirSync(path19.dirname(targetPath), { recursive: true });
13271
+ fs14.copyFileSync(sourcePath, targetPath);
13272
+ const completed = index51 + 1;
13273
+ const percent = 10 + Math.round(completed / total * 55);
13274
+ reportProgress(onProgress, {
13275
+ phase: "copying",
13276
+ completed,
13277
+ total,
13278
+ percent,
13279
+ detail: relativePath
13280
+ });
13281
+ });
13282
+ }
13283
+ function buildZipEntriesWithProgress(sourceRoot, exportFolderName, onProgress) {
13284
+ const files = listRelativeFiles(sourceRoot);
13285
+ const total = Math.max(files.length, 1);
13286
+ return files.map((relativePath, index51) => {
13287
+ const completed = index51 + 1;
13288
+ const percent = 65 + Math.round(completed / total * 30);
13289
+ reportProgress(onProgress, {
13290
+ phase: "zipping",
13291
+ completed,
13292
+ total,
13293
+ percent,
13294
+ detail: relativePath
13295
+ });
13296
+ return {
13297
+ name: path19.posix.join(exportFolderName, relativePath),
13298
+ data: fs14.readFileSync(path19.resolve(sourceRoot, relativePath))
13299
+ };
13300
+ });
12625
13301
  }
12626
- function inspectKitDist(kitId, outDir) {
12627
- const assetRoot = resolveKitAssetRootDist(kitId);
12628
- const manifest = readJsonDist(path17.resolve(assetRoot, "kit.json"));
12629
- const bundleRef = manifest.bundles.find((bundle) => bundle.id === kitId) ?? manifest.bundles[0];
12630
- const bundleManifest = readJsonDist(path17.resolve(assetRoot, bundleRef.path));
12631
- validateKitAssetRootDist(assetRoot, manifest, bundleManifest);
12632
- const outputRoot = resolveKitOutputRootDist(outDir);
13302
+ function downloadBundledKit(kitId, outDir, options = {}) {
13303
+ const resolved = resolveBundledKit(kitId);
13304
+ const outputPaths = resolveOutputPaths(resolved, outDir);
13305
+ const onProgress = options.onProgress;
13306
+ reportProgress(onProgress, {
13307
+ phase: "preparing",
13308
+ completed: 0,
13309
+ total: 1,
13310
+ percent: 0,
13311
+ detail: "Resolving export target"
13312
+ });
13313
+ fs14.mkdirSync(outputPaths.outputRoot, { recursive: true });
13314
+ fs14.rmSync(outputPaths.folderPath, { recursive: true, force: true });
13315
+ copyDirectoryWithProgress(resolved.assetRoot, outputPaths.folderPath, onProgress);
13316
+ const zipBuffer = buildStoredZip(
13317
+ buildZipEntriesWithProgress(outputPaths.folderPath, resolved.bundleManifest.export.folderName, onProgress)
13318
+ );
13319
+ reportProgress(onProgress, {
13320
+ phase: "writing_zip",
13321
+ completed: 1,
13322
+ total: 1,
13323
+ percent: 98,
13324
+ detail: path19.basename(outputPaths.zipPath)
13325
+ });
13326
+ fs14.writeFileSync(outputPaths.zipPath, zipBuffer);
13327
+ reportProgress(onProgress, {
13328
+ phase: "done",
13329
+ completed: 1,
13330
+ total: 1,
13331
+ percent: 100,
13332
+ detail: "Export complete"
13333
+ });
12633
13334
  return {
12634
- assetRoot,
12635
- manifest,
12636
- bundleManifest,
12637
- outputRoot,
12638
- folderPath: path17.resolve(outputRoot, bundleManifest.export.folderName),
12639
- zipPath: path17.resolve(outputRoot, bundleManifest.export.zipFileName)
13335
+ folderPath: outputPaths.folderPath,
13336
+ zipPath: outputPaths.zipPath
12640
13337
  };
12641
13338
  }
12642
- function listBundledKitsDist() {
12643
- const assetBase = path17.resolve(path17.dirname(fileURLToPath2(import.meta.url)), "../assets/worker-kits");
12644
- if (!existsSync2(assetBase)) return [];
12645
- return readdirSync2(assetBase, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => inspectKitDist(entry.name)).sort((a, b) => a.manifest.kit.id.localeCompare(b.manifest.kit.id));
12646
- }
12647
- function downloadKitDist(kitId, outDir) {
12648
- const info = inspectKitDist(kitId, outDir);
12649
- mkdirSync2(info.outputRoot, { recursive: true });
12650
- rmSync(info.folderPath, { recursive: true, force: true });
12651
- copyDirRecursiveDist(info.assetRoot, info.folderPath);
12652
- const zipEntries = listFilesRecursiveDist(info.folderPath).map((relativePath) => ({
12653
- name: path17.posix.join(info.bundleManifest.export.folderName, relativePath),
12654
- data: readFileSync(path17.resolve(info.folderPath, relativePath))
12655
- }));
12656
- writeFileSync(info.zipPath, buildStoredZipDist(zipEntries));
12657
- return info;
12658
- }
12659
- function registerKitCommandsDist(target) {
12660
- const kit = target.command("kit").description("Bundled Growthub Agent Worker Kit export utilities");
12661
- kit.command("list").description("List the bundled worker kits available in this CLI build").action(() => {
12662
- const kits = listBundledKitsDist();
12663
- if (kits.length === 0) {
12664
- console.log(pc21.dim("No bundled worker kits are available in this CLI build."));
13339
+
13340
+ // src/commands/kit.ts
13341
+ var TYPE_CONFIG = {
13342
+ studio: { color: pc23.cyan, emoji: "\u{1F6E0}\uFE0F", label: "Custom Workspaces" },
13343
+ specialized_agents: { color: pc23.magenta, emoji: "\u{1F9E0}", label: "Specialized Agents" },
13344
+ ops: { color: pc23.yellow, emoji: "\u2699\uFE0F ", label: "Ops" }
13345
+ };
13346
+ function displayTypeForFamily(family) {
13347
+ if (family === "workflow" || family === "operator") return "specialized_agents";
13348
+ if (family === "studio" || family === "ops") return family;
13349
+ return family;
13350
+ }
13351
+ function typeColor(family, text58) {
13352
+ const type = displayTypeForFamily(family);
13353
+ return TYPE_CONFIG[type]?.color(text58) ?? text58;
13354
+ }
13355
+ function typeBadge(family) {
13356
+ const type = displayTypeForFamily(family);
13357
+ const cfg = TYPE_CONFIG[type];
13358
+ if (!cfg) return String(type);
13359
+ return cfg.color(`${cfg.emoji} ${cfg.label}`);
13360
+ }
13361
+ function truncate(str, max) {
13362
+ if (str.length <= max) return str;
13363
+ return str.slice(0, max - 1) + "\u2026";
13364
+ }
13365
+ function displayKitName(name) {
13366
+ return name.replace(/^Growthub Agent Worker Kit\s+[—-]\s+/u, "").trim();
13367
+ }
13368
+ function hr(width = 72) {
13369
+ return pc23.dim("\u2500".repeat(width));
13370
+ }
13371
+ function box(lines) {
13372
+ const padded = lines.map((l) => " " + l);
13373
+ const width = Math.max(...padded.map((l) => stripAnsi(l).length)) + 4;
13374
+ const top = pc23.dim("\u250C" + "\u2500".repeat(width) + "\u2510");
13375
+ const bottom = pc23.dim("\u2514" + "\u2500".repeat(width) + "\u2518");
13376
+ const body = padded.map((l) => {
13377
+ const pad = width - stripAnsi(l).length;
13378
+ return pc23.dim("\u2502") + l + " ".repeat(pad) + pc23.dim("\u2502");
13379
+ });
13380
+ return [top, ...body, bottom].join("\n");
13381
+ }
13382
+ function stripAnsi(str) {
13383
+ return str.replace(/\x1B\[[0-9;]*m/g, "");
13384
+ }
13385
+ function terminalLink(label, href) {
13386
+ return `\x1B]8;;${href}\x07${label}\x1B]8;;\x07`;
13387
+ }
13388
+ function folderOpenLabel(folderPath) {
13389
+ const href = pathToFileURL2(folderPath).href;
13390
+ const label = process.platform === "darwin" ? "Open in Finder" : process.platform === "win32" ? "Open in Explorer" : "Open folder";
13391
+ return terminalLink(label, href);
13392
+ }
13393
+ function renderProgressBar(progress) {
13394
+ if (!process.stdout.isTTY) return;
13395
+ const width = 24;
13396
+ const filled = Math.max(0, Math.min(width, Math.round(progress.percent / 100 * width)));
13397
+ const bar = `${"=".repeat(filled)}${"-".repeat(width - filled)}`;
13398
+ const detail = truncate(progress.detail, 48);
13399
+ const line = `\r${pc23.cyan("Exporting kit")} ${pc23.dim("[")}${pc23.green(bar)}${pc23.dim("]")} ${String(progress.percent).padStart(3)}% ${pc23.dim(detail)}`;
13400
+ process.stdout.write(line);
13401
+ if (progress.phase === "done") {
13402
+ process.stdout.write("\n");
13403
+ }
13404
+ }
13405
+ function printKitCard(item) {
13406
+ const badge2 = typeBadge(item.family);
13407
+ console.log("");
13408
+ console.log(box([
13409
+ `${pc23.bold(item.name)} ${pc23.dim("v" + item.version)}`,
13410
+ `${badge2} ${pc23.dim(item.id)}`,
13411
+ "",
13412
+ truncate(item.description, 62),
13413
+ "",
13414
+ `${pc23.dim("Brief:")} ${pc23.dim(item.briefType)} ${pc23.dim("Mode:")} ${pc23.dim(item.executionMode)}`
13415
+ ]));
13416
+ }
13417
+ async function confirmKitActions(input) {
13418
+ const actionLabels = input.actions.map((action) => {
13419
+ if (action === "download") return "download";
13420
+ if (action === "inspect") return "inspect";
13421
+ if (action === "copy-id") return "print id";
13422
+ return action;
13423
+ });
13424
+ const summaryLines = [
13425
+ pc23.bold("Selected kits"),
13426
+ ...input.kits.map((kit) => `${typeBadge(kit.family)} ${displayKitName(kit.name)}`),
13427
+ "",
13428
+ pc23.bold("Selected actions"),
13429
+ actionLabels.join(", ")
13430
+ ];
13431
+ console.log("");
13432
+ console.log(box(summaryLines));
13433
+ const confirmed = await p16.confirm({
13434
+ message: "Continue with these worker kit actions?",
13435
+ initialValue: false
13436
+ });
13437
+ if (p16.isCancel(confirmed)) {
13438
+ p16.cancel("Cancelled.");
13439
+ process.exit(0);
13440
+ }
13441
+ return Boolean(confirmed);
13442
+ }
13443
+ function printGroupedList(kits) {
13444
+ const byType = {};
13445
+ for (const kit of kits) {
13446
+ const type = displayTypeForFamily(kit.family);
13447
+ (byType[type] ??= []).push(kit);
13448
+ }
13449
+ const types = Object.keys(byType).sort();
13450
+ const totalTypes = types.length;
13451
+ console.log("");
13452
+ console.log(
13453
+ pc23.bold("Growthub Agent Worker Kits") + pc23.dim(` ${kits.length} kit${kits.length !== 1 ? "s" : ""} \xB7 ${totalTypes} type${totalTypes !== 1 ? "s" : ""}`)
13454
+ );
13455
+ console.log(hr());
13456
+ for (const type of types) {
13457
+ const groupKits = byType[type];
13458
+ const header = typeBadge(type);
13459
+ console.log(`
13460
+ ${header} ${pc23.dim("(" + groupKits.length + ")")}`);
13461
+ for (const kit of groupKits) {
13462
+ console.log(` ${typeColor(kit.family, pc23.bold(kit.id))} ${pc23.dim("v" + kit.version)}`);
13463
+ console.log(` ${pc23.dim(truncate(kit.description, 62))}`);
13464
+ console.log(` ${pc23.dim("\u2192")} ${pc23.cyan("growthub kit download " + kit.id)}`);
13465
+ console.log("");
13466
+ }
13467
+ }
13468
+ console.log(hr());
13469
+ console.log(pc23.dim(" growthub kit download <id> \xB7 growthub kit inspect <id> \xB7 growthub kit families"));
13470
+ console.log("");
13471
+ }
13472
+ async function runInteractivePicker(opts) {
13473
+ p16.intro(pc23.bold("Growthub Agent Worker Kits"));
13474
+ let kits;
13475
+ try {
13476
+ kits = listBundledKits();
13477
+ } catch (err) {
13478
+ p16.log.error("Failed to load kits: " + err.message);
13479
+ process.exit(1);
13480
+ }
13481
+ const familiesAvailable = [...new Set(kits.map((k) => k.family))].sort();
13482
+ const typeOptions = Array.from(new Set(familiesAvailable.map((family) => displayTypeForFamily(family))));
13483
+ while (true) {
13484
+ const typeChoice = await p16.select({
13485
+ message: "Filter by type",
13486
+ options: [
13487
+ { value: "all", label: "All Types" },
13488
+ ...typeOptions.map((type) => {
13489
+ const cfg = TYPE_CONFIG[type];
13490
+ return {
13491
+ value: type,
13492
+ label: cfg ? cfg.emoji + " " + cfg.label : String(type)
13493
+ };
13494
+ }),
13495
+ ...opts.allowBackToHub ? [{ value: "__back_to_hub", label: "\u2190 Back to main menu" }] : []
13496
+ ]
13497
+ });
13498
+ if (p16.isCancel(typeChoice)) {
13499
+ p16.cancel("Cancelled.");
13500
+ process.exit(0);
13501
+ }
13502
+ if (typeChoice === "__back_to_hub") return "back";
13503
+ const filtered = typeChoice === "all" ? kits : kits.filter((k) => displayTypeForFamily(k.family) === typeChoice);
13504
+ const showTypeBadgeInKitChoices = typeChoice === "all";
13505
+ if (filtered.length === 0) {
13506
+ p16.note("No kits are available for that type yet.", "Nothing found");
13507
+ continue;
13508
+ }
13509
+ while (true) {
13510
+ const kitChoice = await p16.select({
13511
+ message: "Select kit",
13512
+ options: [
13513
+ ...filtered.map((k) => ({
13514
+ value: k.id,
13515
+ label: (showTypeBadgeInKitChoices ? typeBadge(k.family) + " " : "") + pc23.bold(displayKitName(k.name)) + " " + pc23.dim("v" + k.version),
13516
+ hint: truncate(k.description, 55)
13517
+ })),
13518
+ { value: "__back_to_type", label: "\u2190 Back to type filter" }
13519
+ ]
13520
+ });
13521
+ if (p16.isCancel(kitChoice)) {
13522
+ p16.cancel("Cancelled.");
13523
+ process.exit(0);
13524
+ }
13525
+ if (kitChoice === "__back_to_type") break;
13526
+ const selected = filtered.find((kit) => kit.id === kitChoice);
13527
+ if (!selected) {
13528
+ p16.cancel("Selected kit was not found.");
13529
+ process.exit(1);
13530
+ }
13531
+ printKitCard(selected);
13532
+ const nextStep = await p16.select({
13533
+ message: "Next step",
13534
+ options: [
13535
+ { value: "actions", label: "Choose action(s)" },
13536
+ { value: "back_to_kits", label: "\u2190 Back to kit list" }
13537
+ ]
13538
+ });
13539
+ if (p16.isCancel(nextStep)) {
13540
+ p16.cancel("Cancelled.");
13541
+ process.exit(0);
13542
+ }
13543
+ if (nextStep === "back_to_kits") continue;
13544
+ while (true) {
13545
+ const actionOptions = [
13546
+ { value: "download", label: "\u2B07\uFE0F Download kit", hint: "growthub kit download <id>" },
13547
+ { value: "inspect", label: "\u{1F50D} Inspect manifest", hint: "growthub kit inspect <id>" },
13548
+ { value: "copy-id", label: "\u{1F4CB} Print ID to stdout", hint: "echo <kit-id>" }
13549
+ ];
13550
+ const actions = await p16.multiselect({
13551
+ message: "What would you like to do?",
13552
+ options: actionOptions,
13553
+ required: false
13554
+ });
13555
+ if (p16.isCancel(actions)) {
13556
+ p16.cancel("Cancelled.");
13557
+ process.exit(0);
13558
+ }
13559
+ const selectedActions = actions;
13560
+ if (selectedActions.length === 0) {
13561
+ const emptyActionChoice = await p16.select({
13562
+ message: "No actions selected",
13563
+ options: [
13564
+ { value: "retry", label: "Choose action(s)" },
13565
+ { value: "back_to_kits", label: "\u2190 Back to kit list" }
13566
+ ]
13567
+ });
13568
+ if (p16.isCancel(emptyActionChoice)) {
13569
+ p16.cancel("Cancelled.");
13570
+ process.exit(0);
13571
+ }
13572
+ if (emptyActionChoice === "back_to_kits") break;
13573
+ continue;
13574
+ }
13575
+ const confirmed = await confirmKitActions({
13576
+ kits: [selected],
13577
+ actions: selectedActions
13578
+ });
13579
+ if (!confirmed) {
13580
+ const reviewChoice = await p16.select({
13581
+ message: "Review selection",
13582
+ options: [
13583
+ { value: "actions", label: "Choose action(s) again" },
13584
+ { value: "back_to_kits", label: "\u2190 Back to kit list" }
13585
+ ]
13586
+ });
13587
+ if (p16.isCancel(reviewChoice)) {
13588
+ p16.cancel("Cancelled.");
13589
+ process.exit(0);
13590
+ }
13591
+ if (reviewChoice === "back_to_kits") break;
13592
+ continue;
13593
+ }
13594
+ for (const action of selectedActions) {
13595
+ if (action === "copy-id") {
13596
+ console.log(selected.id);
13597
+ continue;
13598
+ }
13599
+ if (action === "inspect") {
13600
+ runInspect(selected.id, opts.out);
13601
+ continue;
13602
+ }
13603
+ if (action === "download") {
13604
+ await runDownload(selected.id, opts);
13605
+ }
13606
+ }
13607
+ if (selectedActions.includes("copy-id")) {
13608
+ p16.outro(pc23.dim("Kit ID printed above."));
13609
+ return "done";
13610
+ }
13611
+ p16.outro(pc23.dim("Done."));
13612
+ return "done";
13613
+ }
13614
+ }
13615
+ }
13616
+ }
13617
+ async function runDownload(kitId, opts) {
13618
+ const resolvedId = fuzzyResolveKitId(kitId);
13619
+ if (!resolvedId) {
13620
+ console.error(pc23.red("Unknown kit '" + kitId + "'.") + pc23.dim(" Run `growthub kit list` to browse."));
13621
+ process.exit(1);
13622
+ }
13623
+ if (resolvedId !== kitId) {
13624
+ console.log(pc23.dim("Resolved '" + kitId + "' \u2192 " + resolvedId));
13625
+ }
13626
+ const kits = listBundledKits();
13627
+ const item = kits.find((k) => k.id === resolvedId);
13628
+ printKitCard(item);
13629
+ if (!opts.yes) {
13630
+ const confirmed = await p16.confirm({ message: "Download " + pc23.bold(displayKitName(item.name)) + "?" });
13631
+ if (p16.isCancel(confirmed) || !confirmed) {
13632
+ p16.cancel("Cancelled.");
13633
+ process.exit(0);
13634
+ }
13635
+ }
13636
+ const result = downloadBundledKit(resolvedId, opts.out, {
13637
+ onProgress: renderProgressBar
13638
+ });
13639
+ const nextSteps = [
13640
+ pc23.bold("Next steps"),
13641
+ "",
13642
+ pc23.dim("1.") + " Point Working Directory at:",
13643
+ " " + pc23.cyan(result.folderPath),
13644
+ "",
13645
+ pc23.dim("2.") + " " + pc23.cyan("cp .env.example .env") + " \u2192 add your API key",
13646
+ pc23.dim("3.") + " " + pc23.cyan("bash setup/clone-fork.sh") + " \u2192 boot local studio",
13647
+ pc23.dim("4.") + " Open Growthub local \u2014 the agent loads automatically",
13648
+ "",
13649
+ pc23.dim("Docs: QUICKSTART.md \xB7 validation-checklist.md")
13650
+ ];
13651
+ console.log("");
13652
+ console.log(box(nextSteps));
13653
+ console.log("");
13654
+ console.log(pc23.bold("Open folder: ") + folderOpenLabel(result.folderPath));
13655
+ console.log(pc23.dim("Folder: ") + result.folderPath);
13656
+ console.log("");
13657
+ console.log(pc23.dim("Zip: ") + result.zipPath);
13658
+ console.log("");
13659
+ }
13660
+ function runInspect(kitId, outDir) {
13661
+ const info = inspectBundledKit(kitId, outDir);
13662
+ const kv = (label, value) => console.log(" " + pc23.bold(label.padEnd(24)) + " " + value);
13663
+ console.log("");
13664
+ console.log(pc23.bold("Kit: " + info.id) + pc23.dim(" v" + info.version));
13665
+ console.log(typeBadge(info.family) + pc23.dim(" schema v" + info.schemaVersion));
13666
+ console.log(hr());
13667
+ kv("Name:", info.name);
13668
+ kv("Description:", truncate(info.description, 55));
13669
+ kv("Entrypoint:", info.entrypointPath);
13670
+ kv("Agent Contract:", info.agentContractPath);
13671
+ kv("Bundle:", info.bundleId + " @ " + info.bundleVersion);
13672
+ kv("Brief Type:", info.briefType);
13673
+ kv("Frozen Assets:", String(info.frozenAssetCount));
13674
+ kv("Required Assets:", String(info.requiredFrozenAssetCount));
13675
+ kv("Export Folder:", info.exportFolderPath);
13676
+ kv("Export Zip:", info.exportZipPath);
13677
+ if (Object.keys(info.compatibility).length > 0) {
13678
+ kv("Compatibility:", JSON.stringify(info.compatibility));
13679
+ }
13680
+ console.log(hr());
13681
+ console.log(pc23.bold(" Required Paths:"));
13682
+ for (const rp of info.requiredPaths) console.log(" " + pc23.dim("\xB7") + " " + rp);
13683
+ console.log("");
13684
+ }
13685
+ function registerKitCommands(program2) {
13686
+ const kit = program2.command("kit").description("Browse, inspect, and download Growthub Agent Worker Kits").addHelpText("after", `
13687
+ Examples:
13688
+ $ growthub kit # interactive browser
13689
+ $ growthub kit list # all kits grouped by type
13690
+ $ growthub kit list --family studio # filter by family
13691
+ $ growthub kit list --json # machine-readable output
13692
+ $ growthub kit download higgsfield # fuzzy slug \u2014 resolves automatically
13693
+ $ growthub kit download growthub-open-higgsfield-studio-v1
13694
+ $ growthub kit inspect higgsfield-studio-v1
13695
+ $ growthub kit families # show family taxonomy
13696
+ `);
13697
+ kit.action(async () => {
13698
+ await runInteractivePicker({});
13699
+ });
13700
+ kit.command("list").description("List all available kits grouped by type").option("--family <families>", "Filter by family (comma-separated: studio,workflow,operator,ops)").option("--json", "Output raw JSON for scripting").addHelpText("after", `
13701
+ Examples:
13702
+ $ growthub kit list
13703
+ $ growthub kit list --family studio
13704
+ $ growthub kit list --family studio,operator
13705
+ $ growthub kit list --json
13706
+ `).action((opts) => {
13707
+ let kits = listBundledKits();
13708
+ if (opts.family) {
13709
+ const wanted = opts.family.split(",").map((f) => f.trim().toLowerCase());
13710
+ kits = kits.filter((k) => wanted.includes(k.family));
13711
+ if (kits.length === 0) {
13712
+ console.error(pc23.yellow("No kits found for family: " + opts.family));
13713
+ console.error(pc23.dim("Valid families: studio, workflow, operator, ops"));
13714
+ process.exitCode = 1;
13715
+ return;
13716
+ }
13717
+ }
13718
+ if (opts.json) {
13719
+ console.log(JSON.stringify(kits, null, 2));
13720
+ return;
13721
+ }
13722
+ printGroupedList(kits);
13723
+ });
13724
+ kit.command("inspect").description("Inspect a kit manifest (supports fuzzy slug)").argument("<kit-id>", "Kit id or slug (e.g. 'higgsfield', 'studio-v1')").option("--out <path>", "Override the export root for resolved paths").option("--json", "Output raw JSON").addHelpText("after", `
13725
+ Examples:
13726
+ $ growthub kit inspect higgsfield-studio-v1
13727
+ $ growthub kit inspect growthub-email-marketing-v1 --json
13728
+ `).action((kitId, opts) => {
13729
+ const resolvedId = fuzzyResolveKitId(kitId);
13730
+ if (!resolvedId) {
13731
+ console.error(pc23.red("Unknown kit '" + kitId + "'.") + pc23.dim(" Run `growthub kit list` to browse."));
13732
+ process.exitCode = 1;
12665
13733
  return;
12666
13734
  }
12667
- for (const item of kits) {
12668
- console.log([
12669
- pc21.bold(item.manifest.kit.id),
12670
- `version=${item.manifest.kit.version}`,
12671
- `bundle=${item.bundleManifest.bundle.id}@${item.bundleManifest.bundle.version}`,
12672
- `briefType=${item.bundleManifest.briefType}`,
12673
- `name=${item.manifest.kit.name}`
12674
- ].join(" "));
13735
+ if (opts.json) {
13736
+ console.log(JSON.stringify(inspectBundledKit(resolvedId, opts.out), null, 2));
13737
+ return;
12675
13738
  }
13739
+ runInspect(resolvedId, opts.out);
13740
+ });
13741
+ kit.command("download").description("Download a kit \u2014 interactive if no kit-id given").argument("[kit-id]", "Kit id or fuzzy slug (omit for interactive picker)").option("--out <path>", "Output directory for the generated artifacts").option("--yes", "Skip confirmation prompt").addHelpText("after", `
13742
+ Examples:
13743
+ $ growthub kit download # interactive
13744
+ $ growthub kit download higgsfield # fuzzy slug
13745
+ $ growthub kit download growthub-open-higgsfield-studio-v1
13746
+ $ growthub kit download studio-v1 --out ~/kits
13747
+ $ growthub kit download studio-v1 --yes
13748
+ `).action(async (kitId, opts) => {
13749
+ if (!kitId) {
13750
+ await runInteractivePicker(opts);
13751
+ return;
13752
+ }
13753
+ const resolvedId = fuzzyResolveKitId(kitId);
13754
+ if (!resolvedId) {
13755
+ console.error(pc23.red("Unknown kit '" + kitId + "'.") + pc23.dim(" Run `growthub kit list` to browse."));
13756
+ process.exitCode = 1;
13757
+ return;
13758
+ }
13759
+ if (opts.yes) {
13760
+ const result = downloadBundledKit(resolvedId, opts.out, {
13761
+ onProgress: renderProgressBar
13762
+ });
13763
+ console.log("");
13764
+ console.log(pc23.bold("Exported folder:"), pc23.cyan(result.folderPath));
13765
+ console.log(pc23.bold("Open folder: "), folderOpenLabel(result.folderPath));
13766
+ console.log(pc23.bold("Zip: "), pc23.dim(result.zipPath));
13767
+ console.log("");
13768
+ console.log(pc23.bold("Next steps:"));
13769
+ console.log(" 1. Point Working Directory at: " + pc23.cyan(result.folderPath));
13770
+ console.log(" 2. " + pc23.cyan("cp .env.example .env") + " \u2192 add your API key");
13771
+ console.log(" 3. " + pc23.cyan("bash setup/clone-fork.sh") + " \u2192 boot local studio");
13772
+ console.log(" 4. Open Growthub local \u2014 the agent loads automatically");
13773
+ console.log("");
13774
+ return;
13775
+ }
13776
+ await runDownload(resolvedId, opts);
13777
+ });
13778
+ kit.command("path").description("Resolve the expected export folder path without exporting").argument("<kit-id>", "Kit id or fuzzy slug").option("--out <path>", "Override the export root").action((kitId, opts) => {
13779
+ const resolvedId = fuzzyResolveKitId(kitId);
13780
+ if (!resolvedId) {
13781
+ console.error(pc23.red("Unknown kit '" + kitId + "'."));
13782
+ process.exitCode = 1;
13783
+ return;
13784
+ }
13785
+ console.log(resolveKitPath(resolvedId, opts.out));
13786
+ });
13787
+ kit.command("validate").description("Validate a kit directory against the kit contract schema").argument("<path>", "Path to the kit directory").addHelpText("after", `
13788
+ Examples:
13789
+ $ growthub kit validate ./my-kit
13790
+ $ growthub kit validate ~/kits/growthub-open-higgsfield-studio-v1
13791
+ `).action((kitPath) => {
13792
+ const resolvedPath = path20.resolve(kitPath);
13793
+ const result = validateKitDirectory(resolvedPath);
13794
+ console.log("");
13795
+ console.log(pc23.bold("Kit: " + result.kitId) + pc23.dim(" schema v" + result.schemaVersion));
13796
+ console.log(hr());
13797
+ for (const w of result.warnings) {
13798
+ console.log(pc23.yellow(" WARN " + w.field + ": " + w.message));
13799
+ }
13800
+ for (const e of result.errors) {
13801
+ console.log(pc23.red(" ERROR " + e.field + ": " + e.message));
13802
+ }
13803
+ if (result.errors.length > 0) {
13804
+ console.log("");
13805
+ console.log(pc23.red(pc23.bold(" Result: INVALID")) + pc23.dim(" (" + result.errors.length + " error" + (result.errors.length !== 1 ? "s" : "") + ")"));
13806
+ process.exitCode = 1;
13807
+ } else {
13808
+ console.log(pc23.green(pc23.bold(" Result: VALID")));
13809
+ }
13810
+ console.log("");
13811
+ });
13812
+ kit.command("families").description("Show the kit family taxonomy with descriptions and examples").action(() => {
13813
+ const defs = [
13814
+ { family: "studio", tagline: "AI generation studio backed by a local fork", surfaces: "local-fork, browser-hosted, desktop-app", example: "growthub-open-higgsfield-studio-v1" },
13815
+ { family: "workflow", tagline: "Multi-step pipeline operator across tools or APIs", surfaces: "browser-hosted (primary)", example: "creative-strategist-v1" },
13816
+ { family: "operator", tagline: "Domain vertical specialist \u2014 one provider, structured deliverables", surfaces: "browser-hosted", example: "growthub-email-marketing-v1" },
13817
+ { family: "ops", tagline: "Infrastructure / toolchain operator (provider optional)", surfaces: "local-fork (primary)", example: "(coming soon)" }
13818
+ ];
13819
+ console.log("");
13820
+ console.log(pc23.bold("Kit Family Taxonomy"));
13821
+ console.log(hr());
13822
+ for (const def of defs) {
13823
+ console.log("\n " + familyBadge(def.family));
13824
+ console.log(" " + pc23.dim(def.tagline));
13825
+ console.log(" " + pc23.dim("Surfaces: ") + pc23.dim(def.surfaces));
13826
+ console.log(" " + pc23.dim("Example: ") + pc23.cyan(def.example));
13827
+ }
13828
+ console.log("");
13829
+ console.log(hr());
13830
+ console.log(pc23.dim(" growthub kit list --family <family> to filter by internal family"));
13831
+ console.log("");
13832
+ });
13833
+ }
13834
+
13835
+ // src/commands/template.ts
13836
+ import path22 from "node:path";
13837
+ import * as p17 from "@clack/prompts";
13838
+ import pc24 from "picocolors";
13839
+
13840
+ // src/templates/service.ts
13841
+ import fs15 from "node:fs";
13842
+ import path21 from "node:path";
13843
+ import { fileURLToPath as fileURLToPath5 } from "node:url";
13844
+
13845
+ // src/templates/catalog.ts
13846
+ var AD_FORMATS = [
13847
+ {
13848
+ type: "ad-format",
13849
+ slug: "bedroom-minimic-talk",
13850
+ id: "ad-formats/bedroom-minimic-talk",
13851
+ name: "Bedroom Mini-Mic Talk",
13852
+ family: "video-creative",
13853
+ category: "Skincare / Beauty Tech / Consumer Product",
13854
+ tags: ["ugc", "skincare", "beauty-tech", "tiktok", "23s", "proven"],
13855
+ scenes: 6,
13856
+ hookVariations: 5,
13857
+ compatibleFormats: [],
13858
+ frozen: true,
13859
+ path: "ad-formats/bedroom-minimic-talk.md"
13860
+ },
13861
+ {
13862
+ type: "ad-format",
13863
+ slug: "villain-animation",
13864
+ id: "ad-formats/villain-animation",
13865
+ name: "Villain Object Animation",
13866
+ family: "video-creative",
13867
+ category: "Pet / Home / Supplement / Displacement products",
13868
+ tags: ["animated", "villain", "long-form", "agitation-stack", "proven"],
13869
+ scenes: 9,
13870
+ hookVariations: 5,
13871
+ compatibleFormats: [],
13872
+ frozen: true,
13873
+ path: "ad-formats/villain-animation.md"
13874
+ },
13875
+ {
13876
+ type: "ad-format",
13877
+ slug: "process-specialist-medical",
13878
+ id: "ad-formats/process-specialist-medical",
13879
+ name: "The Process Specialist",
13880
+ family: "video-creative",
13881
+ category: "Medical / Regenerative Medicine / Healthcare Authority",
13882
+ tags: ["medical", "authority", "doctor", "ugc", "50s", "proven"],
13883
+ scenes: 5,
13884
+ hookVariations: 5,
13885
+ compatibleFormats: [],
13886
+ frozen: true,
13887
+ path: "ad-formats/process-specialist-medical.md"
13888
+ },
13889
+ {
13890
+ type: "ad-format",
13891
+ slug: "frame-analysis",
13892
+ id: "ad-formats/frame-analysis",
13893
+ name: "Frame-by-Frame Analysis Methodology",
13894
+ family: "video-creative",
13895
+ category: "Methodology \u2014 use when no frozen format matches a muse",
13896
+ tags: ["methodology", "muse", "frame-extraction"],
13897
+ scenes: null,
13898
+ hookVariations: null,
13899
+ compatibleFormats: [],
13900
+ frozen: true,
13901
+ path: "ad-formats/frame-analysis.md"
13902
+ }
13903
+ ];
13904
+ var HOOKS = [
13905
+ {
13906
+ type: "scene-module",
13907
+ subtype: "hook",
13908
+ slug: "meme-overlay",
13909
+ id: "scene-modules/hooks/meme-overlay",
13910
+ name: "Meme Overlay Hook",
13911
+ family: "video-creative",
13912
+ category: "Relatable lifestyle pain \u2014 tired, stressed, broke",
13913
+ tags: ["meme", "scene-1", "scroll-stop", "proven"],
13914
+ scenes: null,
13915
+ frozen: true,
13916
+ compatibleFormats: ["bedroom-minimic-talk"],
13917
+ path: "scene-modules/hooks/meme-overlay.md"
13918
+ },
13919
+ {
13920
+ type: "scene-module",
13921
+ subtype: "hook",
13922
+ slug: "tiktok-comment",
13923
+ id: "scene-modules/hooks/tiktok-comment",
13924
+ name: "TikTok Comment Hook",
13925
+ family: "video-creative",
13926
+ category: "High-skepticism categories \u2014 objection-first open",
13927
+ tags: ["tiktok-comment", "scene-1", "skepticism", "proven"],
13928
+ scenes: null,
13929
+ frozen: true,
13930
+ compatibleFormats: ["bedroom-minimic-talk"],
13931
+ path: "scene-modules/hooks/tiktok-comment.md"
13932
+ },
13933
+ {
13934
+ type: "scene-module",
13935
+ subtype: "hook",
13936
+ slug: "pov-confession",
13937
+ id: "scene-modules/hooks/pov-confession",
13938
+ name: "POV Mirror Confession Hook",
13939
+ family: "video-creative",
13940
+ category: "Skincare / Beauty \u2014 female 25\u201335 demo",
13941
+ tags: ["pov", "mirror", "scene-1", "tiktok", "proven"],
13942
+ scenes: null,
13943
+ frozen: true,
13944
+ compatibleFormats: ["bedroom-minimic-talk"],
13945
+ path: "scene-modules/hooks/pov-confession.md"
13946
+ },
13947
+ {
13948
+ type: "scene-module",
13949
+ subtype: "hook",
13950
+ slug: "dollar-amount",
13951
+ id: "scene-modules/hooks/dollar-amount",
13952
+ name: "Dollar Amount Confession Hook",
13953
+ family: "video-creative",
13954
+ category: "Any category where overspending is the shared pain",
13955
+ tags: ["dollar-amount", "scene-1", "cross-format", "proven"],
13956
+ scenes: null,
13957
+ frozen: true,
13958
+ compatibleFormats: ["bedroom-minimic-talk", "villain-animation"],
13959
+ path: "scene-modules/hooks/dollar-amount.md"
13960
+ },
13961
+ {
13962
+ type: "scene-module",
13963
+ subtype: "hook",
13964
+ slug: "villain-hook",
13965
+ id: "scene-modules/hooks/villain-hook",
13966
+ name: "Villain Character Hook",
13967
+ family: "video-creative",
13968
+ category: "Animated \u2014 product displacing an incumbent",
13969
+ tags: ["villain", "animated", "scene-1", "proven"],
13970
+ scenes: null,
13971
+ frozen: true,
13972
+ compatibleFormats: ["villain-animation"],
13973
+ path: "scene-modules/hooks/villain-hook.md"
13974
+ }
13975
+ ];
13976
+ var BODY = [
13977
+ {
13978
+ type: "scene-module",
13979
+ subtype: "body",
13980
+ slug: "minimic-problem",
13981
+ id: "scene-modules/body/minimic-problem",
13982
+ name: "Mini-Mic Problem Confession",
13983
+ family: "video-creative",
13984
+ category: "Authority + failed solutions \u2014 Scene 2",
13985
+ tags: ["minimic", "scene-2", "authority", "proven"],
13986
+ scenes: null,
13987
+ frozen: true,
13988
+ compatibleFormats: ["bedroom-minimic-talk"],
13989
+ path: "scene-modules/body/minimic-problem.md"
13990
+ },
13991
+ {
13992
+ type: "scene-module",
13993
+ subtype: "body",
13994
+ slug: "tiktok-skeptic-pivot",
13995
+ id: "scene-modules/body/tiktok-skeptic-pivot",
13996
+ name: "TikTok Skeptic Pivot",
13997
+ family: "video-creative",
13998
+ category: "Skeptic disarm + product intro \u2014 Scene 3",
13999
+ tags: ["tiktok-comment", "scene-3", "skeptic", "pivot", "proven"],
14000
+ scenes: null,
14001
+ frozen: true,
14002
+ compatibleFormats: ["bedroom-minimic-talk"],
14003
+ path: "scene-modules/body/tiktok-skeptic-pivot.md"
14004
+ },
14005
+ {
14006
+ type: "scene-module",
14007
+ subtype: "body",
14008
+ slug: "product-demo-glow",
14009
+ id: "scene-modules/body/product-demo-glow",
14010
+ name: "Product Demo \u2014 Glow / Active Effect",
14011
+ family: "video-creative",
14012
+ category: "Products with a visible active state \u2014 Scene 4",
14013
+ tags: ["demo", "scene-4", "glow", "active-state", "proven"],
14014
+ scenes: null,
14015
+ frozen: true,
14016
+ compatibleFormats: ["bedroom-minimic-talk"],
14017
+ path: "scene-modules/body/product-demo-glow.md"
14018
+ },
14019
+ {
14020
+ type: "scene-module",
14021
+ subtype: "body",
14022
+ slug: "villain-agitation",
14023
+ id: "scene-modules/body/villain-agitation",
14024
+ name: "Villain Agitation Stack",
14025
+ family: "video-creative",
14026
+ category: "4\xD7 stacked failed solutions \u2014 Scenes 2\u20135",
14027
+ tags: ["villain", "agitation", "scenes-2-5", "animated", "proven"],
14028
+ scenes: null,
14029
+ frozen: true,
14030
+ compatibleFormats: ["villain-animation"],
14031
+ path: "scene-modules/body/villain-agitation.md"
14032
+ },
14033
+ {
14034
+ type: "scene-module",
14035
+ subtype: "body",
14036
+ slug: "before-after-flatlay",
14037
+ id: "scene-modules/body/before-after-flatlay",
14038
+ name: "Before/After + Product Flat Lay",
14039
+ family: "video-creative",
14040
+ category: "Social proof + product authority \u2014 Scene 5",
14041
+ tags: ["before-after", "flatlay", "scene-5", "social-proof", "proven"],
14042
+ scenes: null,
14043
+ frozen: true,
14044
+ compatibleFormats: ["bedroom-minimic-talk"],
14045
+ path: "scene-modules/body/before-after-flatlay.md"
14046
+ }
14047
+ ];
14048
+ var CTA = [
14049
+ {
14050
+ type: "scene-module",
14051
+ subtype: "cta",
14052
+ slug: "bogo-meme-bookend",
14053
+ id: "scene-modules/cta/bogo-meme-bookend",
14054
+ name: "BOGO + Meme Bookend Close",
14055
+ family: "video-creative",
14056
+ category: "BOGO / % off / flash offer \u2014 Scene 6",
14057
+ tags: ["bogo", "meme-bookend", "cta", "proven"],
14058
+ scenes: null,
14059
+ frozen: true,
14060
+ compatibleFormats: ["bedroom-minimic-talk"],
14061
+ path: "scene-modules/cta/bogo-meme-bookend.md"
14062
+ },
14063
+ {
14064
+ type: "scene-module",
14065
+ subtype: "cta",
14066
+ slug: "guarantee-close",
14067
+ id: "scene-modules/cta/guarantee-close",
14068
+ name: "Guarantee Calendar Close",
14069
+ family: "video-creative",
14070
+ category: "30/60-day satisfaction guarantee \u2014 Scene 9",
14071
+ tags: ["guarantee", "calendar", "cta", "animated", "proven"],
14072
+ scenes: null,
14073
+ frozen: true,
14074
+ compatibleFormats: ["villain-animation"],
14075
+ path: "scene-modules/cta/guarantee-close.md"
14076
+ }
14077
+ ];
14078
+ var TEMPLATE_CATALOG = [
14079
+ ...AD_FORMATS,
14080
+ ...HOOKS,
14081
+ ...BODY,
14082
+ ...CTA
14083
+ // ...EMAIL_TEMPLATES,
14084
+ // ...MOTION_TEMPLATES,
14085
+ ];
14086
+
14087
+ // src/templates/service.ts
14088
+ function resolveSharedTemplatesRoot() {
14089
+ const moduleDir = path21.dirname(fileURLToPath5(import.meta.url));
14090
+ for (const candidate of [
14091
+ path21.resolve(moduleDir, "../../assets/shared-templates"),
14092
+ path21.resolve(moduleDir, "../assets/shared-templates")
14093
+ ]) {
14094
+ if (fs15.existsSync(candidate)) return candidate;
14095
+ }
14096
+ throw new Error("Shared template assets not found at cli/assets/shared-templates/");
14097
+ }
14098
+ function resolveSlug(input) {
14099
+ const needle = input.toLowerCase().trim();
14100
+ return TEMPLATE_CATALOG.find((a) => a.id === needle) ?? TEMPLATE_CATALOG.find((a) => a.slug === needle) ?? TEMPLATE_CATALOG.find((a) => a.id.endsWith("/" + needle)) ?? TEMPLATE_CATALOG.find((a) => a.id.includes(needle) || a.slug.includes(needle)) ?? (() => {
14101
+ const tokens = needle.split(/[-_/\s]+/).filter((t) => t.length > 2);
14102
+ for (const token of tokens) {
14103
+ const match = TEMPLATE_CATALOG.find((a) => a.slug.includes(token) || a.id.includes(token));
14104
+ if (match) return match;
14105
+ }
14106
+ return null;
14107
+ })();
14108
+ }
14109
+ function listArtifacts(filter = {}) {
14110
+ let results = [...TEMPLATE_CATALOG];
14111
+ if (filter.type) results = results.filter((a) => a.type === filter.type);
14112
+ if (filter.subtype) results = results.filter((a) => a.type === "scene-module" && a.subtype === filter.subtype);
14113
+ if (filter.family) results = results.filter((a) => a.family === filter.family);
14114
+ if (filter.format) {
14115
+ const fmt = filter.format.toLowerCase();
14116
+ results = results.filter(
14117
+ (a) => a.compatibleFormats.length === 0 || a.compatibleFormats.some((f) => f.includes(fmt))
14118
+ );
14119
+ }
14120
+ if (filter.tags?.length) {
14121
+ results = results.filter((a) => filter.tags.some((tag) => a.tags.includes(tag)));
14122
+ }
14123
+ return results;
14124
+ }
14125
+ function getArtifact(slugOrId) {
14126
+ const artifact = resolveSlug(slugOrId);
14127
+ if (!artifact) throw new Error(`Unknown template '${slugOrId}'. Run 'growthub template list' to browse.`);
14128
+ const root = resolveSharedTemplatesRoot();
14129
+ const absolutePath = path21.resolve(root, artifact.path);
14130
+ if (!fs15.existsSync(absolutePath)) throw new Error(`Template file missing: ${absolutePath}`);
14131
+ return { artifact, content: fs15.readFileSync(absolutePath, "utf8"), absolutePath };
14132
+ }
14133
+ function copyArtifact(slugOrId, destDir) {
14134
+ const resolved = getArtifact(slugOrId);
14135
+ fs15.mkdirSync(destDir, { recursive: true });
14136
+ const destPath = path21.resolve(destDir, path21.basename(resolved.absolutePath));
14137
+ fs15.copyFileSync(resolved.absolutePath, destPath);
14138
+ return destPath;
14139
+ }
14140
+ var GROUP_ORDER = ["ad-formats", "scene-modules/hooks", "scene-modules/body", "scene-modules/cta"];
14141
+ var GROUP_META = {
14142
+ "ad-formats": { label: "Ad Formats", description: "Complete frozen video ad structures \u2014 scene count, sacred elements, adaptation rules" },
14143
+ "scene-modules/hooks": { label: "Scene Modules \u2014 Hooks", description: "Scene 1 \u2014 pattern interrupt, scroll stop, opening emotional beat" },
14144
+ "scene-modules/body": { label: "Scene Modules \u2014 Body", description: "Scenes 2\u2013N \u2014 problem confession, skeptic pivot, demo, social proof" },
14145
+ "scene-modules/cta": { label: "Scene Modules \u2014 CTA", description: "Final scene \u2014 offer close, guarantee, conversion" }
14146
+ };
14147
+ function groupKey(a) {
14148
+ if (a.type === "ad-format") return "ad-formats";
14149
+ return `scene-modules/${a.subtype}`;
14150
+ }
14151
+ function groupArtifacts(artifacts) {
14152
+ const map = /* @__PURE__ */ new Map();
14153
+ for (const a of artifacts) {
14154
+ const key = groupKey(a);
14155
+ if (!map.has(key)) map.set(key, []);
14156
+ map.get(key).push(a);
14157
+ }
14158
+ const ordered = [];
14159
+ for (const key of GROUP_ORDER) {
14160
+ if (!map.has(key)) continue;
14161
+ const items = map.get(key);
14162
+ const meta = GROUP_META[key] ?? { label: key, description: "" };
14163
+ ordered.push({ key, label: meta.label, description: meta.description, count: items.length, artifacts: items });
14164
+ }
14165
+ for (const [key, items] of map) {
14166
+ if (GROUP_ORDER.includes(key)) continue;
14167
+ ordered.push({ key, label: key, description: "", count: items.length, artifacts: items });
14168
+ }
14169
+ return ordered;
14170
+ }
14171
+ function getCatalogStats() {
14172
+ const all = [...TEMPLATE_CATALOG];
14173
+ const byFamily = {};
14174
+ const byType = {};
14175
+ for (const a of all) {
14176
+ byFamily[a.family] = (byFamily[a.family] ?? 0) + 1;
14177
+ byType[a.type] = (byType[a.type] ?? 0) + 1;
14178
+ }
14179
+ return { total: all.length, byFamily, byType };
14180
+ }
14181
+
14182
+ // src/commands/template.ts
14183
+ function stripAnsi2(s) {
14184
+ return s.replace(/\x1B\[[0-9;]*m/g, "");
14185
+ }
14186
+ function hr2(w = 72) {
14187
+ return pc24.dim("\u2500".repeat(w));
14188
+ }
14189
+ function truncate2(s, max) {
14190
+ return s.length <= max ? s : s.slice(0, max - 1) + "\u2026";
14191
+ }
14192
+ function box2(lines) {
14193
+ const padded = lines.map((l) => " " + l);
14194
+ const width = Math.max(...padded.map((l) => stripAnsi2(l).length)) + 4;
14195
+ const top = pc24.dim("\u250C" + "\u2500".repeat(width) + "\u2510");
14196
+ const bottom = pc24.dim("\u2514" + "\u2500".repeat(width) + "\u2518");
14197
+ const body = padded.map((l) => pc24.dim("\u2502") + l + " ".repeat(width - stripAnsi2(l).length) + pc24.dim("\u2502"));
14198
+ return [top, ...body, bottom].join("\n");
14199
+ }
14200
+ function badge(a) {
14201
+ if (a.type === "ad-format") return pc24.cyan("\u{1F3AC} Ad Format");
14202
+ if (a.type === "scene-module") {
14203
+ if (a.subtype === "hook") return pc24.yellow("\u{1FA9D} Hook");
14204
+ if (a.subtype === "body") return pc24.blue("\u{1F9E9} Body");
14205
+ if (a.subtype === "cta") return pc24.green("\u{1F3AF} CTA");
14206
+ }
14207
+ return pc24.magenta("\u{1F9E9} Module");
14208
+ }
14209
+ function printCard(a) {
14210
+ const compat = a.compatibleFormats.length ? pc24.dim("Works with: ") + a.compatibleFormats.map((f) => pc24.cyan(f)).join(", ") : pc24.dim("Works with: any format");
14211
+ const rows = [
14212
+ pc24.bold(a.name),
14213
+ `${badge(a)} ${pc24.dim(a.id)}`,
14214
+ "",
14215
+ truncate2(a.category, 62),
14216
+ "",
14217
+ compat
14218
+ ];
14219
+ if (a.type === "ad-format" && a.scenes != null) {
14220
+ rows.push(pc24.dim("Scenes: ") + a.scenes + (a.hookVariations ? pc24.dim(" \xB7 Hook variations: ") + a.hookVariations : ""));
14221
+ }
14222
+ console.log("");
14223
+ console.log(box2(rows));
14224
+ }
14225
+ function printSummary2(filter) {
14226
+ const artifacts = listArtifacts(filter);
14227
+ if (!artifacts.length) {
14228
+ console.log(pc24.yellow("No templates matched. Try: growthub template list"));
14229
+ return;
14230
+ }
14231
+ const stats = getCatalogStats();
14232
+ const groups = groupArtifacts(artifacts);
14233
+ console.log("");
14234
+ console.log(pc24.bold("Growthub Shared Template Library") + pc24.dim(` ${artifacts.length} of ${stats.total} artifacts`));
14235
+ console.log(pc24.dim(" " + Object.entries(stats.byFamily).map(([f, n]) => `${f} (${n})`).join(" \xB7 ")));
14236
+ console.log(hr2());
14237
+ for (const g of groups) {
14238
+ console.log(`
14239
+ ${pc24.bold(g.label)} ${pc24.dim("(" + g.count + ")")}`);
14240
+ console.log(pc24.dim(" " + g.description));
14241
+ console.log("");
14242
+ for (const a of g.artifacts) {
14243
+ const compat = a.compatibleFormats.length ? pc24.dim(" \xB7 " + a.compatibleFormats.join(", ")) : "";
14244
+ console.log(` ${pc24.cyan(pc24.bold(a.name))}${compat}`);
14245
+ console.log(` ${pc24.dim("growthub template get " + a.slug)}`);
14246
+ console.log("");
14247
+ }
14248
+ }
14249
+ console.log(hr2());
14250
+ console.log(pc24.dim(" growthub template get <slug>"));
14251
+ console.log(pc24.dim(" growthub template list --type ad-formats"));
14252
+ console.log(pc24.dim(" growthub template list --type scene-modules --subtype hooks"));
14253
+ console.log(pc24.dim(" growthub template (interactive picker)"));
14254
+ console.log("");
14255
+ }
14256
+ var TEMPLATE_FAMILY_META = {
14257
+ "video-creative": {
14258
+ label: "Video Ads",
14259
+ emoji: "\u{1F3AC}",
14260
+ hint: "Ad formats, hooks, body modules, and CTA modules"
14261
+ },
14262
+ email: {
14263
+ label: "Email",
14264
+ emoji: "\u2709\uFE0F",
14265
+ hint: "Email-native templates"
14266
+ },
14267
+ motion: {
14268
+ label: "Motion",
14269
+ emoji: "\u{1F39E}\uFE0F",
14270
+ hint: "Motion and animation artifacts"
14271
+ },
14272
+ general: {
14273
+ label: "General",
14274
+ emoji: "\u{1F9E9}",
14275
+ hint: "Shared general-purpose templates"
14276
+ }
14277
+ };
14278
+ async function runTemplatePicker(opts) {
14279
+ p17.intro(pc24.bold("Growthub Shared Template Library"));
14280
+ let artifacts;
14281
+ try {
14282
+ artifacts = listArtifacts();
14283
+ } catch (err) {
14284
+ p17.log.error(err.message);
14285
+ process.exit(1);
14286
+ }
14287
+ const families = [...new Set(artifacts.map((artifact) => artifact.family))];
14288
+ const familyChoice = await p17.select({
14289
+ message: "What template type do you want to browse?",
14290
+ options: [
14291
+ ...families.map((family) => {
14292
+ const meta = TEMPLATE_FAMILY_META[family] ?? {
14293
+ label: family,
14294
+ emoji: "\u{1F9E9}",
14295
+ hint: `${family} templates`
14296
+ };
14297
+ const familyCount = artifacts.filter((artifact) => artifact.family === family).length;
14298
+ return {
14299
+ value: family,
14300
+ label: `${meta.emoji} ${meta.label}`,
14301
+ hint: `${familyCount} available \xB7 ${meta.hint}`
14302
+ };
14303
+ }),
14304
+ ...opts?.allowBackToHub ? [{ value: "__back_to_hub", label: "\u2190 Back to main menu" }] : []
14305
+ ]
14306
+ });
14307
+ if (p17.isCancel(familyChoice)) {
14308
+ p17.cancel("Cancelled.");
14309
+ process.exit(0);
14310
+ }
14311
+ if (familyChoice === "__back_to_hub") return "back";
14312
+ const filteredArtifacts = artifacts.filter((artifact) => artifact.family === familyChoice);
14313
+ const groups = groupArtifacts(filteredArtifacts);
14314
+ const groupChoice = await p17.select({
14315
+ message: "What kind of template?",
14316
+ options: groups.map((g) => ({
14317
+ value: g.key,
14318
+ label: g.label,
14319
+ hint: `${g.count} available \xB7 ${g.description}`
14320
+ }))
14321
+ });
14322
+ if (p17.isCancel(groupChoice)) {
14323
+ p17.cancel("Cancelled.");
14324
+ process.exit(0);
14325
+ }
14326
+ const group = groups.find((g) => g.key === groupChoice);
14327
+ const artifactChoice = await p17.select({
14328
+ message: `Select from: ${group.label}`,
14329
+ options: group.artifacts.map((a) => ({
14330
+ value: a.id,
14331
+ label: pc24.bold(a.name),
14332
+ hint: truncate2(a.category, 52)
14333
+ }))
14334
+ });
14335
+ if (p17.isCancel(artifactChoice)) {
14336
+ p17.cancel("Cancelled.");
14337
+ process.exit(0);
14338
+ }
14339
+ const selected = filteredArtifacts.find((a) => a.id === artifactChoice);
14340
+ printCard(selected);
14341
+ const action = await p17.select({
14342
+ message: "What would you like to do?",
14343
+ options: [
14344
+ { value: "print", label: "\u{1F4C4} Print to terminal" },
14345
+ { value: "copy", label: "\u{1F4C1} Copy to directory" },
14346
+ { value: "slug", label: "\u{1F4CB} Print slug" },
14347
+ { value: "cancel", label: "Cancel" }
14348
+ ]
12676
14349
  });
12677
- kit.command("inspect").description("Inspect a bundled worker kit manifest and export metadata").argument("<kit-id>", "Bundled worker kit id").option("--out <path>", "Override the export root used for resolved output paths").action((kitId, opts) => {
12678
- const info = inspectKitDist(kitId, opts.out);
12679
- console.log(`Kit: ${info.manifest.kit.id} @ ${info.manifest.kit.version}`);
12680
- console.log(`Name: ${info.manifest.kit.name}`);
12681
- console.log(`Bundle: ${info.bundleManifest.bundle.id} @ ${info.bundleManifest.bundle.version}`);
12682
- console.log(`Entrypoint: ${info.manifest.entrypoint.path}`);
12683
- console.log(`Export Folder: ${info.folderPath}`);
12684
- console.log(`Export Zip: ${info.zipPath}`);
14350
+ if (p17.isCancel(action) || action === "cancel") {
14351
+ p17.cancel("Cancelled.");
14352
+ process.exit(0);
14353
+ }
14354
+ if (action === "slug") {
14355
+ console.log(selected.slug);
14356
+ p17.outro(pc24.dim("Use with: growthub template get " + selected.slug));
14357
+ return "done";
14358
+ }
14359
+ if (action === "print") {
14360
+ const r = getArtifact(selected.id);
14361
+ console.log("\n" + hr2());
14362
+ console.log(r.content);
14363
+ console.log(hr2());
14364
+ p17.outro(pc24.dim("Source: " + r.absolutePath));
14365
+ return "done";
14366
+ }
14367
+ if (action === "copy") {
14368
+ const destInput = await p17.text({
14369
+ message: "Output directory:",
14370
+ placeholder: "~/Downloads/templates",
14371
+ validate: (v) => !v?.trim() ? "Path is required" : void 0
14372
+ });
14373
+ if (p17.isCancel(destInput)) {
14374
+ p17.cancel("Cancelled.");
14375
+ process.exit(0);
14376
+ }
14377
+ const destDir = path22.resolve(destInput.replace(/^~/, process.env["HOME"] ?? ""));
14378
+ const destPath = copyArtifact(selected.id, destDir);
14379
+ p17.outro(pc24.green("Copied \u2192 ") + destPath);
14380
+ return "done";
14381
+ }
14382
+ return "done";
14383
+ }
14384
+ function registerTemplateCommands(program2) {
14385
+ const cmd = program2.command("template").description("Browse and pull from the shared creative template library").addHelpText("after", `
14386
+ Shared templates are frozen artifact primitives \u2014 distinct from kits.
14387
+ Any agent or kit resolves them by slug.
14388
+
14389
+ $ growthub template Interactive picker
14390
+ $ growthub template list Grouped summary
14391
+ $ growthub template list --type ad-formats
14392
+ $ growthub template list --type scene-modules --subtype hooks
14393
+ $ growthub template list --format villain-animation
14394
+ $ growthub template get villain-animation Fuzzy slug
14395
+ $ growthub template get meme-overlay --out ~/kit/hooks/
14396
+ $ growthub template get villain-animation --json
14397
+ `);
14398
+ cmd.action(async () => {
14399
+ await runTemplatePicker();
12685
14400
  });
12686
- kit.command("download").description("Export a bundled worker kit as both a zip file and expanded folder").argument("<kit-id>", "Bundled worker kit id").option("--out <path>", "Output directory for the generated artifacts").action((kitId, opts) => {
12687
- const info = downloadKitDist(kitId, opts.out);
12688
- console.log(`Expanded Folder: ${info.folderPath}`);
12689
- console.log(`Zip File: ${info.zipPath}`);
14401
+ cmd.command("list").description("Grouped template summary \u2014 filter before browsing").option("--type <type>", "ad-formats | scene-modules").option("--subtype <subtype>", "hooks | body | cta (scene-modules only)").option("--format <format>", "Filter by compatible ad format slug").option("--json", "Raw JSON for scripting").action((opts) => {
14402
+ const filter = {};
14403
+ if (opts.type) {
14404
+ const t = opts.type.replace(/s$/, "");
14405
+ if (t !== "ad-format" && t !== "scene-module") {
14406
+ console.error(pc24.red(`Unknown --type '${opts.type}'.`) + pc24.dim(" Valid: ad-formats, scene-modules"));
14407
+ process.exitCode = 1;
14408
+ return;
14409
+ }
14410
+ filter.type = t;
14411
+ }
14412
+ if (opts.subtype) {
14413
+ const sub = opts.subtype.replace(/s$/, "");
14414
+ if (!["hook", "body", "cta"].includes(sub)) {
14415
+ console.error(pc24.red(`Unknown --subtype '${opts.subtype}'.`) + pc24.dim(" Valid: hooks, body, cta"));
14416
+ process.exitCode = 1;
14417
+ return;
14418
+ }
14419
+ filter.subtype = sub;
14420
+ }
14421
+ if (opts.format) filter.format = opts.format;
14422
+ if (opts.json) {
14423
+ console.log(JSON.stringify(listArtifacts(filter), null, 2));
14424
+ return;
14425
+ }
14426
+ printSummary2(filter);
12690
14427
  });
12691
- kit.command("path").description("Resolve the expected expanded export folder path without exporting").argument("<kit-id>", "Bundled worker kit id").option("--out <path>", "Output directory for the generated artifacts").action((kitId, opts) => {
12692
- const info = inspectKitDist(kitId, opts.out);
12693
- console.log(info.folderPath);
14428
+ cmd.command("get").description("Print or copy a template \u2014 fuzzy slug resolution").argument("<slug>", "Artifact slug (e.g. villain-animation, meme-overlay)").option("--out <path>", "Copy to this directory").option("--json", "Artifact metadata + content as JSON").action((slug, opts) => {
14429
+ const artifact = resolveSlug(slug);
14430
+ if (!artifact) {
14431
+ console.error(pc24.red(`Unknown template '${slug}'.`) + pc24.dim(" Run `growthub template list` to browse."));
14432
+ process.exitCode = 1;
14433
+ return;
14434
+ }
14435
+ if (artifact.id !== slug && artifact.slug !== slug) {
14436
+ console.error(pc24.dim(`Resolved '${slug}' \u2192 ${artifact.slug}`));
14437
+ }
14438
+ let resolved;
14439
+ try {
14440
+ resolved = getArtifact(artifact.id);
14441
+ } catch (err) {
14442
+ console.error(pc24.red(err.message));
14443
+ process.exitCode = 1;
14444
+ return;
14445
+ }
14446
+ if (opts.json) {
14447
+ console.log(JSON.stringify({ artifact: resolved.artifact, content: resolved.content }, null, 2));
14448
+ return;
14449
+ }
14450
+ if (opts.out) {
14451
+ const destDir = path22.resolve(opts.out.replace(/^~/, process.env["HOME"] ?? ""));
14452
+ try {
14453
+ const dest = copyArtifact(artifact.id, destDir);
14454
+ console.log(pc24.green("Copied \u2192 ") + dest);
14455
+ } catch (err) {
14456
+ console.error(pc24.red(err.message));
14457
+ process.exitCode = 1;
14458
+ }
14459
+ return;
14460
+ }
14461
+ printCard(resolved.artifact);
14462
+ console.log(hr2());
14463
+ console.log(resolved.content);
14464
+ console.log(hr2());
14465
+ console.log(pc24.dim("Source: " + resolved.absolutePath));
14466
+ console.log("");
12694
14467
  });
12695
14468
  }
12696
14469
 
12697
14470
  // src/index.ts
14471
+ init_banner();
14472
+ init_home();
12698
14473
  var program = new Command();
12699
14474
  var DATA_DIR_OPTION_HELP = "Growthub data directory root (isolates local instance state)";
14475
+ function resolveSurfaceProfile(config) {
14476
+ if (typeof config !== "object" || config === null) return null;
14477
+ const surface = config.surface;
14478
+ if (typeof surface !== "object" || surface === null) return null;
14479
+ const profile = surface.profile;
14480
+ return profile === "dx" || profile === "gtm" ? profile : null;
14481
+ }
12700
14482
  function resolveBootstrapOptions(argv) {
12701
14483
  const options = {};
12702
- for (let index50 = 0; index50 < argv.length; index50 += 1) {
12703
- const value = argv[index50];
12704
- if ((value === "-c" || value === "--config") && argv[index50 + 1]) {
12705
- options.config = argv[index50 + 1];
12706
- index50 += 1;
14484
+ for (let index51 = 0; index51 < argv.length; index51 += 1) {
14485
+ const value = argv[index51];
14486
+ if ((value === "-c" || value === "--config") && argv[index51 + 1]) {
14487
+ options.config = argv[index51 + 1];
14488
+ index51 += 1;
12707
14489
  continue;
12708
14490
  }
12709
- if ((value === "-d" || value === "--data-dir") && argv[index50 + 1]) {
12710
- options.dataDir = argv[index50 + 1];
12711
- index50 += 1;
14491
+ if ((value === "-d" || value === "--data-dir") && argv[index51 + 1]) {
14492
+ options.dataDir = argv[index51 + 1];
14493
+ index51 += 1;
12712
14494
  }
12713
14495
  }
12714
14496
  return options;
@@ -12725,10 +14507,201 @@ function registerSharedCommands(target) {
12725
14507
  });
12726
14508
  target.command("allowed-hostname").description("Allow a hostname for authenticated/private mode access").argument("<host>", "Hostname to allow (for example dotta-macbook-pro)").option("-c, --config <path>", "Path to config file").option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP).action(addAllowedHostname);
12727
14509
  target.command("run").description("Bootstrap local setup (onboard + doctor) and run Growthub").option("-c, --config <path>", "Path to config file").option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP).option("-i, --instance <id>", "Local instance id (default: default)").option("--repair", "Attempt automatic repairs during doctor", true).option("--no-repair", "Disable automatic repairs during doctor").action(runCommand);
12728
- registerKitCommandsDist(target);
14510
+ target.command("discover").description("Shared discovery entry for local app install, worker kits, and templates").option("-c, --config <path>", "Path to config file").option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP).option("--run", "Start Growthub immediately after saving config", false).action(async (opts) => {
14511
+ await runDiscoveryHub(opts);
14512
+ });
14513
+ registerKitCommands(target);
14514
+ registerTemplateCommands(target);
12729
14515
  const auth = target.command("auth").description("Authentication and bootstrap utilities");
12730
14516
  auth.command("bootstrap-ceo").description("Create a one-time bootstrap invite URL for first instance admin").option("-c, --config <path>", "Path to config file").option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP).option("--force", "Create new invite even if admin already exists", false).option("--expires-hours <hours>", "Invite expiration window in hours", (value) => Number(value)).option("--base-url <url>", "Public base URL used to print invite link").action(bootstrapCeoInvite);
12731
14517
  }
14518
+ async function runDiscoveryHub(opts) {
14519
+ printPaperclipCliBanner();
14520
+ p18.intro("Growthub Local");
14521
+ while (true) {
14522
+ const surfaceChoice = await p18.select({
14523
+ message: "What do you want to do first?",
14524
+ options: [
14525
+ {
14526
+ value: "app",
14527
+ label: "\u{1F4E6} Full Local App",
14528
+ hint: "Work from existing app or build from scratch"
14529
+ },
14530
+ {
14531
+ value: "kits",
14532
+ label: "\u{1F9F0} Worker Kits",
14533
+ hint: "Self-contained workspace environments for agents"
14534
+ },
14535
+ {
14536
+ value: "templates",
14537
+ label: "\u{1F4DA} Templates",
14538
+ hint: "Artifact template library"
14539
+ },
14540
+ {
14541
+ value: "help",
14542
+ label: "\u2753 Help CLI",
14543
+ hint: "See the main commands and what each path does"
14544
+ }
14545
+ ]
14546
+ });
14547
+ if (p18.isCancel(surfaceChoice)) {
14548
+ p18.cancel("Cancelled.");
14549
+ process.exit(0);
14550
+ }
14551
+ if (surfaceChoice === "help") {
14552
+ p18.note(
14553
+ [
14554
+ "\u{1F4E6} Full Local App: open an existing local surface or create a new GTM/DX profile.",
14555
+ "\u{1F9F0} Worker Kits: browse specialized agents and custom workspaces.",
14556
+ "\u{1F4DA} Templates: browse reusable artifact templates by library type.",
14557
+ "",
14558
+ "Direct commands:",
14559
+ "growthub run",
14560
+ "growthub kit",
14561
+ "growthub template",
14562
+ "growthub doctor",
14563
+ "growthub configure"
14564
+ ].join("\n"),
14565
+ "Growthub CLI Help"
14566
+ );
14567
+ continue;
14568
+ }
14569
+ if (surfaceChoice === "app") {
14570
+ while (true) {
14571
+ const appModeChoice = await p18.select({
14572
+ message: "How do you want to open Growthub Local?",
14573
+ options: [
14574
+ {
14575
+ value: "create",
14576
+ label: "\u{1F195} Create New Profile",
14577
+ hint: "Build a new local app surface."
14578
+ },
14579
+ {
14580
+ value: "load",
14581
+ label: "\u{1F4C2} Load Existing Profile",
14582
+ hint: "Work from a profile already on this machine."
14583
+ },
14584
+ {
14585
+ value: "__back_to_hub",
14586
+ label: "\u2190 Back to main menu"
14587
+ }
14588
+ ]
14589
+ });
14590
+ if (p18.isCancel(appModeChoice)) {
14591
+ p18.cancel("Cancelled.");
14592
+ process.exit(0);
14593
+ }
14594
+ if (appModeChoice === "__back_to_hub") break;
14595
+ if (appModeChoice === "load") {
14596
+ const existingSurfaces = listLocalSurfaces();
14597
+ if (existingSurfaces.length === 0) {
14598
+ p18.note("No existing local app profiles were found on this machine.", "Nothing found");
14599
+ continue;
14600
+ }
14601
+ const existingChoice = await p18.select({
14602
+ message: "Select an existing app surface",
14603
+ options: [
14604
+ ...existingSurfaces.map((surface) => ({
14605
+ value: surface.instanceId,
14606
+ label: `${surface.profile === "gtm" ? "\u{1F4C8}" : "\u{1F9E0}"} ${surface.profile.toUpperCase()} \xB7 ${surface.instanceId}`,
14607
+ hint: surface.configPath
14608
+ })),
14609
+ { value: "__back_to_app_mode", label: "\u2190 Back to app options" }
14610
+ ]
14611
+ });
14612
+ if (p18.isCancel(existingChoice)) {
14613
+ p18.cancel("Cancelled.");
14614
+ process.exit(0);
14615
+ }
14616
+ if (existingChoice === "__back_to_app_mode") {
14617
+ continue;
14618
+ }
14619
+ const selectedSurface = existingSurfaces.find((surface) => surface.instanceId === existingChoice);
14620
+ if (!selectedSurface) {
14621
+ p18.cancel("Selected profile not found.");
14622
+ process.exit(1);
14623
+ }
14624
+ process.env.PAPERCLIP_SURFACE_PROFILE = selectedSurface.profile;
14625
+ await runCommand({
14626
+ config: selectedSurface.configPath,
14627
+ instance: selectedSurface.instanceId,
14628
+ repair: true,
14629
+ yes: true
14630
+ });
14631
+ return;
14632
+ }
14633
+ const profileChoice = await p18.select({
14634
+ message: "Which new app surface do you want to create?",
14635
+ options: [
14636
+ {
14637
+ value: "gtm",
14638
+ label: "\u{1F4C8} GTM",
14639
+ hint: "Go-to-Market surface."
14640
+ },
14641
+ {
14642
+ value: "dx",
14643
+ label: "\u{1F9E0} DX",
14644
+ hint: "Developer Experience surface."
14645
+ },
14646
+ {
14647
+ value: "__back_to_app_mode",
14648
+ label: "\u2190 Back to app options"
14649
+ }
14650
+ ]
14651
+ });
14652
+ if (p18.isCancel(profileChoice)) {
14653
+ p18.cancel("Cancelled.");
14654
+ process.exit(0);
14655
+ }
14656
+ if (profileChoice === "__back_to_app_mode") {
14657
+ continue;
14658
+ }
14659
+ process.env.PAPERCLIP_SURFACE_PROFILE = profileChoice;
14660
+ await onboard({
14661
+ config: opts?.config,
14662
+ run: opts?.run ?? isInstallerMode(),
14663
+ yes: isInstallerMode()
14664
+ });
14665
+ return;
14666
+ }
14667
+ continue;
14668
+ }
14669
+ if (surfaceChoice === "kits") {
14670
+ const result2 = await runInteractivePicker({ allowBackToHub: true });
14671
+ if (result2 === "back") continue;
14672
+ return;
14673
+ }
14674
+ const result = await runTemplatePicker({ allowBackToHub: true });
14675
+ if (result === "back") continue;
14676
+ return;
14677
+ }
14678
+ }
14679
+ function isInstallerMode() {
14680
+ return process.env.GROWTHUB_INSTALLER_MODE === "true";
14681
+ }
14682
+ function listLocalSurfaces() {
14683
+ const homeDir = resolvePaperclipHomeDir();
14684
+ const instancesDir = path23.resolve(homeDir, "instances");
14685
+ if (!fs16.existsSync(instancesDir)) return [];
14686
+ return fs16.readdirSync(instancesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => {
14687
+ const instanceId = entry.name;
14688
+ const configPath = path23.resolve(instancesDir, instanceId, "config.json");
14689
+ if (!fs16.existsSync(configPath)) return null;
14690
+ try {
14691
+ const config = readConfig(configPath);
14692
+ if (!config) return null;
14693
+ const profile = resolveSurfaceProfile(config);
14694
+ if (!profile) return null;
14695
+ return {
14696
+ instanceId,
14697
+ profile,
14698
+ configPath
14699
+ };
14700
+ } catch {
14701
+ return null;
14702
+ }
14703
+ }).filter((entry) => entry !== null).sort((left, right) => left.instanceId.localeCompare(right.instanceId));
14704
+ }
12732
14705
  function registerDxCommands(target) {
12733
14706
  const heartbeat = target.command("heartbeat").description("Heartbeat utilities");
12734
14707
  heartbeat.command("run").description("Run one agent heartbeat and stream live logs").requiredOption("-a, --agent-id <agentId>", "Agent ID to invoke").option("-c, --config <path>", "Path to config file").option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP).option("--context <path>", "Path to CLI context file").option("--profile <name>", "CLI context profile name").option("--api-base <url>", "Base URL for the Growthub server API").option("--api-key <token>", "Bearer token for agent-authenticated calls").option(
@@ -12753,8 +14726,45 @@ applyDataDirOverride(bootstrapOptions, {
12753
14726
  });
12754
14727
  loadPaperclipEnvFile(bootstrapOptions.config);
12755
14728
  var bootstrapConfig = readConfig(resolveConfigPath(bootstrapOptions.config));
12756
- var surfaceRuntime = initializeSurfaceRuntimeContract(bootstrapConfig?.surface.profile);
12757
- program.name("growthub").description("Growthub CLI \u2014 setup, diagnose, and configure your instance").version("0.2.7");
14729
+ var surfaceRuntime = initializeSurfaceRuntimeContract(resolveSurfaceProfile(bootstrapConfig) ?? void 0);
14730
+ program.name("growthub").description("Growthub CLI \u2014 setup, configure, and run your local Growthub instance").version("0.3.43").addHelpText("after", `
14731
+ Worker Kits (agent execution environments):
14732
+
14733
+ Discovery:
14734
+ $ growthub kit Interactive browser \u2014 pick, preview, download
14735
+ $ growthub kit list All kits grouped by family (studio \xB7 workflow \xB7 operator \xB7 ops)
14736
+ $ growthub kit list --family studio Filter by family
14737
+ $ growthub kit families Show family taxonomy with descriptions
14738
+
14739
+ Download:
14740
+ $ growthub kit download Interactive (no arg = picker)
14741
+ $ growthub kit download higgsfield Fuzzy slug \u2014 resolves automatically
14742
+ $ growthub kit download higgsfield --yes Skip confirmation (scripting / agent use)
14743
+ $ growthub kit download growthub-open-higgsfield-studio-v1 --out ~/kits
14744
+
14745
+ Inspect & validate:
14746
+ $ growthub kit inspect higgsfield-studio-v1
14747
+ $ growthub kit inspect growthub-email-marketing-v1 --json
14748
+ $ growthub kit validate ./path/to/kit
14749
+
14750
+ After download:
14751
+ 1. Point Growthub local (or Claude Code) Working Directory at the exported folder
14752
+ 2. cp .env.example .env \u2192 add your API key
14753
+ 3. Open a new session \u2014 the operator agent loads automatically
14754
+
14755
+ Instance setup:
14756
+ $ growthub onboard First-run interactive wizard
14757
+ $ growthub run Onboard + doctor + start server
14758
+ $ growthub doctor Diagnose and optionally repair
14759
+ $ growthub configure Update config sections
14760
+ $ growthub Interactive discovery hub
14761
+ `);
14762
+ program.action(async () => {
14763
+ await runDiscoveryHub();
14764
+ });
14765
+ program.command("list").description("Open the interactive Growthub discovery hub").action(async () => {
14766
+ await runDiscoveryHub();
14767
+ });
12758
14768
  program.hook("preAction", (_thisCommand, actionCommand) => {
12759
14769
  const options = actionCommand.optsWithGlobals();
12760
14770
  const optionNames = new Set(actionCommand.options.map((option) => option.attributeName()));
@@ -12774,4 +14784,3 @@ program.parseAsync().catch((err) => {
12774
14784
  console.error(err instanceof Error ? err.message : String(err));
12775
14785
  process.exit(1);
12776
14786
  });
12777
- //# sourceMappingURL=index.js.map