bopodev-db 0.1.25 → 0.1.27

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.
@@ -1,5 +1,5 @@
1
1
 
2
2
  
3
- > bopodev-db@0.1.25 build /Users/danielkrusenstrahle/Documents/Projects/Monorepo/bopohq/packages/db
3
+ > bopodev-db@0.1.27 build /Users/danielkrusenstrahle/Documents/Projects/Monorepo/bopohq/packages/db
4
4
  > tsc -p tsconfig.json --emitDeclarationOnly
5
5
 
@@ -1,4 +1,4 @@
1
1
 
2
- > bopodev-db@0.1.24 typecheck /Users/danielkrusenstrahle/Documents/Projects/Monorepo/bopohq/packages/db
2
+ > bopodev-db@0.1.26 typecheck /Users/danielkrusenstrahle/Documents/Projects/Monorepo/bopohq/packages/db
3
3
  > tsc -p tsconfig.json --noEmit
4
4
 
package/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # `packages/db`
2
+
3
+ Database schema and repository layer for Bopo, backed by Drizzle + PGlite.
4
+
5
+ ## Responsibilities
6
+
7
+ - Define schema models and migrations/bootstrap behavior.
8
+ - Expose repository functions used by API services/routes.
9
+ - Provide typed DB access primitives for shared business logic.
10
+
11
+ ## Usage
12
+
13
+ Primary consumer is `apps/api`.
14
+
15
+ ## Commands
16
+
17
+ - `pnpm --filter bopodev-db build`
18
+ - `pnpm --filter bopodev-db typecheck`
19
+
20
+ ## Notes
21
+
22
+ - Default DB path is managed by app/runtime config; see configuration docs before overriding.
23
+ - API startup bootstraps DB and registers built-in plugins/templates.
24
+
25
+ ## Related Docs
26
+
27
+ - `docs/developer/architecture.md`
28
+ - `docs/developer/configuration-reference.md`
29
+ - `docs/operations/deployment.md`
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./bootstrap";
2
2
  export * from "./client";
3
+ export { resolveDefaultDbPath, resolveBopoInstanceRoot } from "./default-paths";
3
4
  export * from "./repositories";
4
5
  export * from "./schema";
@@ -326,6 +326,23 @@ export declare function listIssues(db: BopoDb, companyId: string, projectId?: st
326
326
  createdAt: Date;
327
327
  updatedAt: Date;
328
328
  }[]>;
329
+ export declare function getIssue(db: BopoDb, companyId: string, issueId: string): Promise<{
330
+ id: string;
331
+ companyId: string;
332
+ projectId: string;
333
+ parentIssueId: string | null;
334
+ title: string;
335
+ body: string | null;
336
+ status: string;
337
+ priority: string;
338
+ assigneeAgentId: string | null;
339
+ labelsJson: string;
340
+ tagsJson: string;
341
+ isClaimed: boolean;
342
+ claimedByHeartbeatRunId: string | null;
343
+ createdAt: Date;
344
+ updatedAt: Date;
345
+ } | null>;
329
346
  export declare function createIssue(db: BopoDb, input: {
330
347
  companyId: string;
331
348
  projectId: string;
@@ -872,11 +889,13 @@ export declare function markAttentionInboxResolved(db: BopoDb, input: {
872
889
  }): Promise<void>;
873
890
  export declare function appendCost(db: BopoDb, input: {
874
891
  companyId: string;
892
+ runId?: string | null;
875
893
  providerType: string;
876
894
  runtimeModelId?: string | null;
877
895
  pricingProviderType?: string | null;
878
896
  pricingModelId?: string | null;
879
897
  pricingSource?: "exact" | "missing" | null;
898
+ usdCostStatus?: "exact" | "estimated" | "unknown" | null;
880
899
  tokenInput: number;
881
900
  tokenOutput: number;
882
901
  usdCost: string;
@@ -887,6 +906,7 @@ export declare function appendCost(db: BopoDb, input: {
887
906
  export declare function listCostEntries(db: BopoDb, companyId: string, limit?: number): Promise<{
888
907
  id: string;
889
908
  companyId: string;
909
+ runId: string | null;
890
910
  projectId: string | null;
891
911
  issueId: string | null;
892
912
  agentId: string | null;
@@ -898,6 +918,7 @@ export declare function listCostEntries(db: BopoDb, companyId: string, limit?: n
898
918
  tokenInput: number;
899
919
  tokenOutput: number;
900
920
  usdCost: string;
921
+ usdCostStatus: string | null;
901
922
  createdAt: Date;
902
923
  }[]>;
903
924
  export declare function listHeartbeatRuns(db: BopoDb, companyId: string, limit?: number): Promise<{
@@ -1429,39 +1450,3 @@ export declare function createTemplateInstall(db: BopoDb, input: {
1429
1450
  templateVersionId: string | null;
1430
1451
  summaryJson: string;
1431
1452
  } | null>;
1432
- export declare function listModelPricing(db: BopoDb, companyId: string): Promise<{
1433
- companyId: string;
1434
- providerType: string;
1435
- modelId: string;
1436
- displayName: string | null;
1437
- inputUsdPer1M: string;
1438
- outputUsdPer1M: string;
1439
- currency: string;
1440
- updatedAt: Date;
1441
- updatedBy: string | null;
1442
- }[]>;
1443
- export declare function getModelPricing(db: BopoDb, input: {
1444
- companyId: string;
1445
- providerType: string;
1446
- modelId: string;
1447
- }): Promise<{
1448
- companyId: string;
1449
- providerType: string;
1450
- modelId: string;
1451
- displayName: string | null;
1452
- inputUsdPer1M: string;
1453
- outputUsdPer1M: string;
1454
- currency: string;
1455
- updatedAt: Date;
1456
- updatedBy: string | null;
1457
- } | null>;
1458
- export declare function upsertModelPricing(db: BopoDb, input: {
1459
- companyId: string;
1460
- providerType: string;
1461
- modelId: string;
1462
- displayName?: string | null;
1463
- inputUsdPer1M?: string | null;
1464
- outputUsdPer1M?: string | null;
1465
- currency?: string | null;
1466
- updatedBy?: string | null;
1467
- }): Promise<void>;
package/dist/schema.d.ts CHANGED
@@ -2980,6 +2980,23 @@ export declare const costLedger: import("drizzle-orm/pg-core").PgTableWithColumn
2980
2980
  identity: undefined;
2981
2981
  generated: undefined;
2982
2982
  }, {}, {}>;
2983
+ runId: import("drizzle-orm/pg-core").PgColumn<{
2984
+ name: "run_id";
2985
+ tableName: "cost_ledger";
2986
+ dataType: "string";
2987
+ columnType: "PgText";
2988
+ data: string;
2989
+ driverParam: string;
2990
+ notNull: false;
2991
+ hasDefault: false;
2992
+ isPrimaryKey: false;
2993
+ isAutoincrement: false;
2994
+ hasRuntimeDefault: false;
2995
+ enumValues: [string, ...string[]];
2996
+ baseColumn: never;
2997
+ identity: undefined;
2998
+ generated: undefined;
2999
+ }, {}, {}>;
2983
3000
  projectId: import("drizzle-orm/pg-core").PgColumn<{
2984
3001
  name: "project_id";
2985
3002
  tableName: "cost_ledger";
@@ -3167,6 +3184,23 @@ export declare const costLedger: import("drizzle-orm/pg-core").PgTableWithColumn
3167
3184
  identity: undefined;
3168
3185
  generated: undefined;
3169
3186
  }, {}, {}>;
3187
+ usdCostStatus: import("drizzle-orm/pg-core").PgColumn<{
3188
+ name: "usd_cost_status";
3189
+ tableName: "cost_ledger";
3190
+ dataType: "string";
3191
+ columnType: "PgText";
3192
+ data: string;
3193
+ driverParam: string;
3194
+ notNull: false;
3195
+ hasDefault: false;
3196
+ isPrimaryKey: false;
3197
+ isAutoincrement: false;
3198
+ hasRuntimeDefault: false;
3199
+ enumValues: [string, ...string[]];
3200
+ baseColumn: never;
3201
+ identity: undefined;
3202
+ generated: undefined;
3203
+ }, {}, {}>;
3170
3204
  createdAt: import("drizzle-orm/pg-core").PgColumn<{
3171
3205
  name: "created_at";
3172
3206
  tableName: "cost_ledger";
@@ -4004,166 +4038,6 @@ export declare const templateInstalls: import("drizzle-orm/pg-core").PgTableWith
4004
4038
  };
4005
4039
  dialect: "pg";
4006
4040
  }>;
4007
- export declare const modelPricing: import("drizzle-orm/pg-core").PgTableWithColumns<{
4008
- name: "model_pricing";
4009
- schema: undefined;
4010
- columns: {
4011
- companyId: import("drizzle-orm/pg-core").PgColumn<{
4012
- name: "company_id";
4013
- tableName: "model_pricing";
4014
- dataType: "string";
4015
- columnType: "PgText";
4016
- data: string;
4017
- driverParam: string;
4018
- notNull: true;
4019
- hasDefault: false;
4020
- isPrimaryKey: false;
4021
- isAutoincrement: false;
4022
- hasRuntimeDefault: false;
4023
- enumValues: [string, ...string[]];
4024
- baseColumn: never;
4025
- identity: undefined;
4026
- generated: undefined;
4027
- }, {}, {}>;
4028
- providerType: import("drizzle-orm/pg-core").PgColumn<{
4029
- name: "provider_type";
4030
- tableName: "model_pricing";
4031
- dataType: "string";
4032
- columnType: "PgText";
4033
- data: string;
4034
- driverParam: string;
4035
- notNull: true;
4036
- hasDefault: false;
4037
- isPrimaryKey: false;
4038
- isAutoincrement: false;
4039
- hasRuntimeDefault: false;
4040
- enumValues: [string, ...string[]];
4041
- baseColumn: never;
4042
- identity: undefined;
4043
- generated: undefined;
4044
- }, {}, {}>;
4045
- modelId: import("drizzle-orm/pg-core").PgColumn<{
4046
- name: "model_id";
4047
- tableName: "model_pricing";
4048
- dataType: "string";
4049
- columnType: "PgText";
4050
- data: string;
4051
- driverParam: string;
4052
- notNull: true;
4053
- hasDefault: false;
4054
- isPrimaryKey: false;
4055
- isAutoincrement: false;
4056
- hasRuntimeDefault: false;
4057
- enumValues: [string, ...string[]];
4058
- baseColumn: never;
4059
- identity: undefined;
4060
- generated: undefined;
4061
- }, {}, {}>;
4062
- displayName: import("drizzle-orm/pg-core").PgColumn<{
4063
- name: "display_name";
4064
- tableName: "model_pricing";
4065
- dataType: "string";
4066
- columnType: "PgText";
4067
- data: string;
4068
- driverParam: string;
4069
- notNull: false;
4070
- hasDefault: false;
4071
- isPrimaryKey: false;
4072
- isAutoincrement: false;
4073
- hasRuntimeDefault: false;
4074
- enumValues: [string, ...string[]];
4075
- baseColumn: never;
4076
- identity: undefined;
4077
- generated: undefined;
4078
- }, {}, {}>;
4079
- inputUsdPer1M: import("drizzle-orm/pg-core").PgColumn<{
4080
- name: "input_usd_per_1m";
4081
- tableName: "model_pricing";
4082
- dataType: "string";
4083
- columnType: "PgNumeric";
4084
- data: string;
4085
- driverParam: string;
4086
- notNull: true;
4087
- hasDefault: true;
4088
- isPrimaryKey: false;
4089
- isAutoincrement: false;
4090
- hasRuntimeDefault: false;
4091
- enumValues: undefined;
4092
- baseColumn: never;
4093
- identity: undefined;
4094
- generated: undefined;
4095
- }, {}, {}>;
4096
- outputUsdPer1M: import("drizzle-orm/pg-core").PgColumn<{
4097
- name: "output_usd_per_1m";
4098
- tableName: "model_pricing";
4099
- dataType: "string";
4100
- columnType: "PgNumeric";
4101
- data: string;
4102
- driverParam: string;
4103
- notNull: true;
4104
- hasDefault: true;
4105
- isPrimaryKey: false;
4106
- isAutoincrement: false;
4107
- hasRuntimeDefault: false;
4108
- enumValues: undefined;
4109
- baseColumn: never;
4110
- identity: undefined;
4111
- generated: undefined;
4112
- }, {}, {}>;
4113
- currency: import("drizzle-orm/pg-core").PgColumn<{
4114
- name: "currency";
4115
- tableName: "model_pricing";
4116
- dataType: "string";
4117
- columnType: "PgText";
4118
- data: string;
4119
- driverParam: string;
4120
- notNull: true;
4121
- hasDefault: true;
4122
- isPrimaryKey: false;
4123
- isAutoincrement: false;
4124
- hasRuntimeDefault: false;
4125
- enumValues: [string, ...string[]];
4126
- baseColumn: never;
4127
- identity: undefined;
4128
- generated: undefined;
4129
- }, {}, {}>;
4130
- updatedAt: import("drizzle-orm/pg-core").PgColumn<{
4131
- name: "updated_at";
4132
- tableName: "model_pricing";
4133
- dataType: "date";
4134
- columnType: "PgTimestamp";
4135
- data: Date;
4136
- driverParam: string;
4137
- notNull: true;
4138
- hasDefault: true;
4139
- isPrimaryKey: false;
4140
- isAutoincrement: false;
4141
- hasRuntimeDefault: false;
4142
- enumValues: undefined;
4143
- baseColumn: never;
4144
- identity: undefined;
4145
- generated: undefined;
4146
- }, {}, {}>;
4147
- updatedBy: import("drizzle-orm/pg-core").PgColumn<{
4148
- name: "updated_by";
4149
- tableName: "model_pricing";
4150
- dataType: "string";
4151
- columnType: "PgText";
4152
- data: string;
4153
- driverParam: string;
4154
- notNull: false;
4155
- hasDefault: false;
4156
- isPrimaryKey: false;
4157
- isAutoincrement: false;
4158
- hasRuntimeDefault: false;
4159
- enumValues: [string, ...string[]];
4160
- baseColumn: never;
4161
- identity: undefined;
4162
- generated: undefined;
4163
- }, {}, {}>;
4164
- };
4165
- dialect: "pg";
4166
- }>;
4167
4041
  export declare const pluginConfigs: import("drizzle-orm/pg-core").PgTableWithColumns<{
4168
4042
  name: "plugin_configs";
4169
4043
  schema: undefined;
@@ -7348,6 +7222,23 @@ export declare const schema: {
7348
7222
  identity: undefined;
7349
7223
  generated: undefined;
7350
7224
  }, {}, {}>;
7225
+ runId: import("drizzle-orm/pg-core").PgColumn<{
7226
+ name: "run_id";
7227
+ tableName: "cost_ledger";
7228
+ dataType: "string";
7229
+ columnType: "PgText";
7230
+ data: string;
7231
+ driverParam: string;
7232
+ notNull: false;
7233
+ hasDefault: false;
7234
+ isPrimaryKey: false;
7235
+ isAutoincrement: false;
7236
+ hasRuntimeDefault: false;
7237
+ enumValues: [string, ...string[]];
7238
+ baseColumn: never;
7239
+ identity: undefined;
7240
+ generated: undefined;
7241
+ }, {}, {}>;
7351
7242
  projectId: import("drizzle-orm/pg-core").PgColumn<{
7352
7243
  name: "project_id";
7353
7244
  tableName: "cost_ledger";
@@ -7535,6 +7426,23 @@ export declare const schema: {
7535
7426
  identity: undefined;
7536
7427
  generated: undefined;
7537
7428
  }, {}, {}>;
7429
+ usdCostStatus: import("drizzle-orm/pg-core").PgColumn<{
7430
+ name: "usd_cost_status";
7431
+ tableName: "cost_ledger";
7432
+ dataType: "string";
7433
+ columnType: "PgText";
7434
+ data: string;
7435
+ driverParam: string;
7436
+ notNull: false;
7437
+ hasDefault: false;
7438
+ isPrimaryKey: false;
7439
+ isAutoincrement: false;
7440
+ hasRuntimeDefault: false;
7441
+ enumValues: [string, ...string[]];
7442
+ baseColumn: never;
7443
+ identity: undefined;
7444
+ generated: undefined;
7445
+ }, {}, {}>;
7538
7446
  createdAt: import("drizzle-orm/pg-core").PgColumn<{
7539
7447
  name: "created_at";
7540
7448
  tableName: "cost_ledger";
@@ -8692,166 +8600,6 @@ export declare const schema: {
8692
8600
  };
8693
8601
  dialect: "pg";
8694
8602
  }>;
8695
- modelPricing: import("drizzle-orm/pg-core").PgTableWithColumns<{
8696
- name: "model_pricing";
8697
- schema: undefined;
8698
- columns: {
8699
- companyId: import("drizzle-orm/pg-core").PgColumn<{
8700
- name: "company_id";
8701
- tableName: "model_pricing";
8702
- dataType: "string";
8703
- columnType: "PgText";
8704
- data: string;
8705
- driverParam: string;
8706
- notNull: true;
8707
- hasDefault: false;
8708
- isPrimaryKey: false;
8709
- isAutoincrement: false;
8710
- hasRuntimeDefault: false;
8711
- enumValues: [string, ...string[]];
8712
- baseColumn: never;
8713
- identity: undefined;
8714
- generated: undefined;
8715
- }, {}, {}>;
8716
- providerType: import("drizzle-orm/pg-core").PgColumn<{
8717
- name: "provider_type";
8718
- tableName: "model_pricing";
8719
- dataType: "string";
8720
- columnType: "PgText";
8721
- data: string;
8722
- driverParam: string;
8723
- notNull: true;
8724
- hasDefault: false;
8725
- isPrimaryKey: false;
8726
- isAutoincrement: false;
8727
- hasRuntimeDefault: false;
8728
- enumValues: [string, ...string[]];
8729
- baseColumn: never;
8730
- identity: undefined;
8731
- generated: undefined;
8732
- }, {}, {}>;
8733
- modelId: import("drizzle-orm/pg-core").PgColumn<{
8734
- name: "model_id";
8735
- tableName: "model_pricing";
8736
- dataType: "string";
8737
- columnType: "PgText";
8738
- data: string;
8739
- driverParam: string;
8740
- notNull: true;
8741
- hasDefault: false;
8742
- isPrimaryKey: false;
8743
- isAutoincrement: false;
8744
- hasRuntimeDefault: false;
8745
- enumValues: [string, ...string[]];
8746
- baseColumn: never;
8747
- identity: undefined;
8748
- generated: undefined;
8749
- }, {}, {}>;
8750
- displayName: import("drizzle-orm/pg-core").PgColumn<{
8751
- name: "display_name";
8752
- tableName: "model_pricing";
8753
- dataType: "string";
8754
- columnType: "PgText";
8755
- data: string;
8756
- driverParam: string;
8757
- notNull: false;
8758
- hasDefault: false;
8759
- isPrimaryKey: false;
8760
- isAutoincrement: false;
8761
- hasRuntimeDefault: false;
8762
- enumValues: [string, ...string[]];
8763
- baseColumn: never;
8764
- identity: undefined;
8765
- generated: undefined;
8766
- }, {}, {}>;
8767
- inputUsdPer1M: import("drizzle-orm/pg-core").PgColumn<{
8768
- name: "input_usd_per_1m";
8769
- tableName: "model_pricing";
8770
- dataType: "string";
8771
- columnType: "PgNumeric";
8772
- data: string;
8773
- driverParam: string;
8774
- notNull: true;
8775
- hasDefault: true;
8776
- isPrimaryKey: false;
8777
- isAutoincrement: false;
8778
- hasRuntimeDefault: false;
8779
- enumValues: undefined;
8780
- baseColumn: never;
8781
- identity: undefined;
8782
- generated: undefined;
8783
- }, {}, {}>;
8784
- outputUsdPer1M: import("drizzle-orm/pg-core").PgColumn<{
8785
- name: "output_usd_per_1m";
8786
- tableName: "model_pricing";
8787
- dataType: "string";
8788
- columnType: "PgNumeric";
8789
- data: string;
8790
- driverParam: string;
8791
- notNull: true;
8792
- hasDefault: true;
8793
- isPrimaryKey: false;
8794
- isAutoincrement: false;
8795
- hasRuntimeDefault: false;
8796
- enumValues: undefined;
8797
- baseColumn: never;
8798
- identity: undefined;
8799
- generated: undefined;
8800
- }, {}, {}>;
8801
- currency: import("drizzle-orm/pg-core").PgColumn<{
8802
- name: "currency";
8803
- tableName: "model_pricing";
8804
- dataType: "string";
8805
- columnType: "PgText";
8806
- data: string;
8807
- driverParam: string;
8808
- notNull: true;
8809
- hasDefault: true;
8810
- isPrimaryKey: false;
8811
- isAutoincrement: false;
8812
- hasRuntimeDefault: false;
8813
- enumValues: [string, ...string[]];
8814
- baseColumn: never;
8815
- identity: undefined;
8816
- generated: undefined;
8817
- }, {}, {}>;
8818
- updatedAt: import("drizzle-orm/pg-core").PgColumn<{
8819
- name: "updated_at";
8820
- tableName: "model_pricing";
8821
- dataType: "date";
8822
- columnType: "PgTimestamp";
8823
- data: Date;
8824
- driverParam: string;
8825
- notNull: true;
8826
- hasDefault: true;
8827
- isPrimaryKey: false;
8828
- isAutoincrement: false;
8829
- hasRuntimeDefault: false;
8830
- enumValues: undefined;
8831
- baseColumn: never;
8832
- identity: undefined;
8833
- generated: undefined;
8834
- }, {}, {}>;
8835
- updatedBy: import("drizzle-orm/pg-core").PgColumn<{
8836
- name: "updated_by";
8837
- tableName: "model_pricing";
8838
- dataType: "string";
8839
- columnType: "PgText";
8840
- data: string;
8841
- driverParam: string;
8842
- notNull: false;
8843
- hasDefault: false;
8844
- isPrimaryKey: false;
8845
- isAutoincrement: false;
8846
- hasRuntimeDefault: false;
8847
- enumValues: [string, ...string[]];
8848
- baseColumn: never;
8849
- identity: undefined;
8850
- generated: undefined;
8851
- }, {}, {}>;
8852
- };
8853
- dialect: "pg";
8854
- }>;
8855
8603
  agentIssueLabels: import("drizzle-orm/pg-core").PgTableWithColumns<{
8856
8604
  name: "agent_issue_labels";
8857
8605
  schema: undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bopodev-db",
3
- "version": "0.1.25",
3
+ "version": "0.1.27",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/bootstrap.ts CHANGED
@@ -371,6 +371,7 @@ export async function bootstrapDatabase(dbPath?: string) {
371
371
  CREATE TABLE IF NOT EXISTS cost_ledger (
372
372
  id TEXT PRIMARY KEY,
373
373
  company_id TEXT NOT NULL REFERENCES companies(id) ON DELETE CASCADE,
374
+ run_id TEXT REFERENCES heartbeat_runs(id) ON DELETE SET NULL,
374
375
  project_id TEXT REFERENCES projects(id) ON DELETE SET NULL,
375
376
  issue_id TEXT REFERENCES issues(id) ON DELETE SET NULL,
376
377
  agent_id TEXT REFERENCES agents(id) ON DELETE SET NULL,
@@ -382,9 +383,14 @@ export async function bootstrapDatabase(dbPath?: string) {
382
383
  token_input INTEGER NOT NULL DEFAULT 0,
383
384
  token_output INTEGER NOT NULL DEFAULT 0,
384
385
  usd_cost NUMERIC(12, 6) NOT NULL DEFAULT 0,
386
+ usd_cost_status TEXT,
385
387
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
386
388
  );
387
389
  `);
390
+ await db.execute(sql`
391
+ ALTER TABLE cost_ledger
392
+ ADD COLUMN IF NOT EXISTS run_id TEXT REFERENCES heartbeat_runs(id) ON DELETE SET NULL;
393
+ `);
388
394
  await db.execute(sql`
389
395
  ALTER TABLE cost_ledger
390
396
  ADD COLUMN IF NOT EXISTS runtime_model_id TEXT;
@@ -402,18 +408,11 @@ export async function bootstrapDatabase(dbPath?: string) {
402
408
  ADD COLUMN IF NOT EXISTS pricing_source TEXT;
403
409
  `);
404
410
  await db.execute(sql`
405
- CREATE TABLE IF NOT EXISTS model_pricing (
406
- company_id TEXT NOT NULL REFERENCES companies(id) ON DELETE CASCADE,
407
- provider_type TEXT NOT NULL,
408
- model_id TEXT NOT NULL,
409
- display_name TEXT,
410
- input_usd_per_1m NUMERIC(12, 6) NOT NULL DEFAULT 0,
411
- output_usd_per_1m NUMERIC(12, 6) NOT NULL DEFAULT 0,
412
- currency TEXT NOT NULL DEFAULT 'USD',
413
- updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
414
- updated_by TEXT,
415
- PRIMARY KEY (company_id, provider_type, model_id)
416
- );
411
+ ALTER TABLE cost_ledger
412
+ ADD COLUMN IF NOT EXISTS usd_cost_status TEXT;
413
+ `);
414
+ await db.execute(sql`
415
+ DROP TABLE IF EXISTS model_pricing;
417
416
  `);
418
417
  await db.execute(sql`
419
418
  CREATE TABLE IF NOT EXISTS audit_events (
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./bootstrap";
2
2
  export * from "./client";
3
+ export { resolveDefaultDbPath, resolveBopoInstanceRoot } from "./default-paths";
3
4
  export * from "./repositories";
4
5
  export * from "./schema";
@@ -17,7 +17,6 @@ import {
17
17
  issueAttachments,
18
18
  issueComments,
19
19
  issues,
20
- modelPricing,
21
20
  pluginConfigs,
22
21
  pluginRuns,
23
22
  plugins,
@@ -541,6 +540,15 @@ export async function listIssues(db: BopoDb, companyId: string, projectId?: stri
541
540
  return db.select().from(issues).where(where).orderBy(desc(issues.updatedAt));
542
541
  }
543
542
 
543
+ export async function getIssue(db: BopoDb, companyId: string, issueId: string) {
544
+ const [row] = await db
545
+ .select()
546
+ .from(issues)
547
+ .where(and(eq(issues.companyId, companyId), eq(issues.id, issueId)))
548
+ .limit(1);
549
+ return row ?? null;
550
+ }
551
+
544
552
  export async function createIssue(
545
553
  db: BopoDb,
546
554
  input: {
@@ -1458,11 +1466,13 @@ export async function appendCost(
1458
1466
  db: BopoDb,
1459
1467
  input: {
1460
1468
  companyId: string;
1469
+ runId?: string | null;
1461
1470
  providerType: string;
1462
1471
  runtimeModelId?: string | null;
1463
1472
  pricingProviderType?: string | null;
1464
1473
  pricingModelId?: string | null;
1465
1474
  pricingSource?: "exact" | "missing" | null;
1475
+ usdCostStatus?: "exact" | "estimated" | "unknown" | null;
1466
1476
  tokenInput: number;
1467
1477
  tokenOutput: number;
1468
1478
  usdCost: string;
@@ -1475,11 +1485,13 @@ export async function appendCost(
1475
1485
  await db.insert(costLedger).values({
1476
1486
  id,
1477
1487
  companyId: input.companyId,
1488
+ runId: input.runId ?? null,
1478
1489
  providerType: input.providerType,
1479
1490
  runtimeModelId: input.runtimeModelId ?? null,
1480
1491
  pricingProviderType: input.pricingProviderType ?? null,
1481
1492
  pricingModelId: input.pricingModelId ?? null,
1482
1493
  pricingSource: input.pricingSource ?? null,
1494
+ usdCostStatus: input.usdCostStatus ?? null,
1483
1495
  tokenInput: input.tokenInput,
1484
1496
  tokenOutput: input.tokenOutput,
1485
1497
  usdCost: input.usdCost,
@@ -2367,70 +2379,6 @@ export async function createTemplateInstall(
2367
2379
  return row ?? null;
2368
2380
  }
2369
2381
 
2370
- export async function listModelPricing(db: BopoDb, companyId: string) {
2371
- return db
2372
- .select()
2373
- .from(modelPricing)
2374
- .where(eq(modelPricing.companyId, companyId))
2375
- .orderBy(asc(modelPricing.providerType), asc(modelPricing.modelId));
2376
- }
2377
-
2378
- export async function getModelPricing(
2379
- db: BopoDb,
2380
- input: { companyId: string; providerType: string; modelId: string }
2381
- ) {
2382
- const rows = await db
2383
- .select()
2384
- .from(modelPricing)
2385
- .where(
2386
- and(
2387
- eq(modelPricing.companyId, input.companyId),
2388
- eq(modelPricing.providerType, input.providerType),
2389
- eq(modelPricing.modelId, input.modelId)
2390
- )
2391
- )
2392
- .limit(1);
2393
- return rows[0] ?? null;
2394
- }
2395
-
2396
- export async function upsertModelPricing(
2397
- db: BopoDb,
2398
- input: {
2399
- companyId: string;
2400
- providerType: string;
2401
- modelId: string;
2402
- displayName?: string | null;
2403
- inputUsdPer1M?: string | null;
2404
- outputUsdPer1M?: string | null;
2405
- currency?: string | null;
2406
- updatedBy?: string | null;
2407
- }
2408
- ) {
2409
- await db
2410
- .insert(modelPricing)
2411
- .values({
2412
- companyId: input.companyId,
2413
- providerType: input.providerType,
2414
- modelId: input.modelId,
2415
- displayName: input.displayName ?? null,
2416
- inputUsdPer1M: input.inputUsdPer1M ?? "0.000000",
2417
- outputUsdPer1M: input.outputUsdPer1M ?? "0.000000",
2418
- currency: input.currency ?? "USD",
2419
- updatedBy: input.updatedBy ?? null
2420
- })
2421
- .onConflictDoUpdate({
2422
- target: [modelPricing.companyId, modelPricing.providerType, modelPricing.modelId],
2423
- set: compactUpdate({
2424
- displayName: input.displayName ?? null,
2425
- inputUsdPer1M: input.inputUsdPer1M ?? "0.000000",
2426
- outputUsdPer1M: input.outputUsdPer1M ?? "0.000000",
2427
- currency: input.currency ?? "USD",
2428
- updatedBy: input.updatedBy ?? null,
2429
- updatedAt: touchUpdatedAtSql
2430
- })
2431
- });
2432
- }
2433
-
2434
2382
  function compactUpdate<T extends Record<string, unknown>>(input: T) {
2435
2383
  return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== undefined));
2436
2384
  }
package/src/schema.ts CHANGED
@@ -280,6 +280,7 @@ export const costLedger = pgTable("cost_ledger", {
280
280
  companyId: text("company_id")
281
281
  .notNull()
282
282
  .references(() => companies.id, { onDelete: "cascade" }),
283
+ runId: text("run_id").references(() => heartbeatRuns.id, { onDelete: "set null" }),
283
284
  projectId: text("project_id").references(() => projects.id, { onDelete: "set null" }),
284
285
  issueId: text("issue_id").references(() => issues.id, { onDelete: "set null" }),
285
286
  agentId: text("agent_id").references(() => agents.id, { onDelete: "set null" }),
@@ -291,6 +292,7 @@ export const costLedger = pgTable("cost_ledger", {
291
292
  tokenInput: integer("token_input").notNull().default(0),
292
293
  tokenOutput: integer("token_output").notNull().default(0),
293
294
  usdCost: numeric("usd_cost", { precision: 12, scale: 6 }).notNull().default("0"),
295
+ usdCostStatus: text("usd_cost_status"),
294
296
  createdAt: timestamp("created_at", { mode: "date" }).defaultNow().notNull()
295
297
  });
296
298
 
@@ -365,24 +367,6 @@ export const templateInstalls = pgTable("template_installs", {
365
367
  createdAt: timestamp("created_at", { mode: "date" }).defaultNow().notNull()
366
368
  });
367
369
 
368
- export const modelPricing = pgTable(
369
- "model_pricing",
370
- {
371
- companyId: text("company_id")
372
- .notNull()
373
- .references(() => companies.id, { onDelete: "cascade" }),
374
- providerType: text("provider_type").notNull(),
375
- modelId: text("model_id").notNull(),
376
- displayName: text("display_name"),
377
- inputUsdPer1M: numeric("input_usd_per_1m", { precision: 12, scale: 6 }).notNull().default("0"),
378
- outputUsdPer1M: numeric("output_usd_per_1m", { precision: 12, scale: 6 }).notNull().default("0"),
379
- currency: text("currency").notNull().default("USD"),
380
- updatedAt: timestamp("updated_at", { mode: "date" }).defaultNow().notNull(),
381
- updatedBy: text("updated_by")
382
- },
383
- (table) => [primaryKey({ columns: [table.companyId, table.providerType, table.modelId] })]
384
- );
385
-
386
370
  export const pluginConfigs = pgTable(
387
371
  "plugin_configs",
388
372
  {
@@ -456,7 +440,6 @@ export const schema = {
456
440
  templates,
457
441
  templateVersions,
458
442
  templateInstalls,
459
- modelPricing,
460
443
  agentIssueLabels,
461
444
  projectWorkspaces
462
445
  };