@wirecat/cli-core 0.558.0 → 0.560.0

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 (92) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/dist/background/schedules.d.ts +2 -0
  3. package/dist/cli/effects.d.ts +13 -2
  4. package/dist/cli/effects.js +23 -2
  5. package/dist/cli/index.d.ts +2 -2
  6. package/dist/cli/index.js +2 -2
  7. package/dist/cli/meeting-findings-input.d.ts +3 -0
  8. package/dist/cli/meeting-findings-input.js +4 -0
  9. package/dist/cli/messenger/conversation-answers.d.ts +3 -0
  10. package/dist/cli/messenger/message-answers.d.ts +3 -0
  11. package/dist/cli/messenger/message-writes.d.ts +6 -0
  12. package/dist/cli/schedule/schedule-command.d.ts +6 -1
  13. package/dist/cli/schedule/schedule-command.js +24 -2
  14. package/dist/domain/records.d.ts +161 -0
  15. package/dist/domain/records.js +234 -0
  16. package/dist/entities/contact-context.d.ts +6 -0
  17. package/dist/entities/conversation-results.d.ts +6 -0
  18. package/dist/entities/evidence.d.ts +24 -0
  19. package/dist/entities/index.d.ts +190 -0
  20. package/dist/entities/index.js +3 -0
  21. package/dist/entities/listener.d.ts +12 -0
  22. package/dist/entities/mail-findings.d.ts +116 -0
  23. package/dist/entities/mail-findings.js +68 -0
  24. package/dist/entities/message-context.d.ts +9 -0
  25. package/dist/entities/message-write.d.ts +12 -0
  26. package/dist/entities/message.d.ts +6 -0
  27. package/dist/entities/message.js +6 -0
  28. package/dist/entities/store-records.d.ts +3 -0
  29. package/dist/errors/reasons.js +11 -0
  30. package/dist/index.d.ts +1 -0
  31. package/dist/index.js +1 -0
  32. package/dist/mail/cli/marks.d.ts +1 -0
  33. package/dist/mail/cli/marks.js +11 -4
  34. package/dist/mail/cli/review.js +10 -2
  35. package/dist/mail/findings.d.ts +55 -0
  36. package/dist/mail/findings.js +140 -0
  37. package/dist/mail/index.d.ts +2 -1
  38. package/dist/mail/index.js +2 -1
  39. package/dist/mail/marks.d.ts +10 -3
  40. package/dist/mail/marks.js +34 -5
  41. package/dist/meetings/findings-rules.d.ts +24 -0
  42. package/dist/meetings/findings-rules.js +136 -116
  43. package/dist/meetings/index.d.ts +2 -1
  44. package/dist/meetings/index.js +2 -1
  45. package/dist/meetings/mcp/index.d.ts +15 -15
  46. package/dist/runs/secrets.d.ts +2 -0
  47. package/dist/runs/secrets.js +2 -0
  48. package/dist/services/index.d.ts +1 -0
  49. package/dist/services/index.js +1 -0
  50. package/dist/services/ingest.d.ts +45 -0
  51. package/dist/services/ingest.js +80 -0
  52. package/dist/services/proposals/kinds/mail-findings.d.ts +8 -0
  53. package/dist/services/proposals/kinds/mail-findings.js +87 -0
  54. package/dist/services/proposals/registry.js +3 -1
  55. package/dist/services/proposals/types.d.ts +2 -0
  56. package/dist/store/decisions.d.ts +1 -1
  57. package/dist/store/decisions.js +1 -1
  58. package/dist/store/index.d.ts +2 -0
  59. package/dist/store/index.js +1 -0
  60. package/dist/store/mail-findings.d.ts +51 -0
  61. package/dist/store/mail-findings.js +1 -0
  62. package/dist/store/path.d.ts +2 -0
  63. package/dist/store/path.js +21 -1
  64. package/dist/store/sqlite/accounts.js +4 -0
  65. package/dist/store/sqlite/email-activity.d.ts +8 -0
  66. package/dist/store/sqlite/email-activity.js +31 -5
  67. package/dist/store/sqlite/findings-core.d.ts +1 -0
  68. package/dist/store/sqlite/findings-core.js +1 -1
  69. package/dist/store/sqlite/mail-findings.d.ts +3 -0
  70. package/dist/store/sqlite/mail-findings.js +333 -0
  71. package/dist/store/sqlite/manifest.js +2 -0
  72. package/dist/store/sqlite/memories.d.ts +4 -1
  73. package/dist/store/sqlite/memories.js +48 -43
  74. package/dist/store/sqlite/migrations.generated.js +16 -0
  75. package/dist/store/sqlite/open-store.d.ts +1 -1
  76. package/dist/store/sqlite/open-store.js +4 -1
  77. package/dist/store/sqlite/open.js +2 -1
  78. package/dist/store/sqlite/proposed-actions.js +2 -1
  79. package/dist/store/sqlite/records.d.ts +81 -0
  80. package/dist/store/sqlite/records.js +372 -0
  81. package/dist/store/sqlite/schema.d.ts +353 -0
  82. package/dist/store/sqlite/schema.js +37 -0
  83. package/dist/store/sqlite/tasks.d.ts +2 -0
  84. package/dist/store/sqlite/tasks.js +26 -24
  85. package/dist/store/sqlite/test-accounts.d.ts +8 -0
  86. package/dist/store/sqlite/test-accounts.js +31 -0
  87. package/dist/store/sqlite/work-tasks.d.ts +1 -0
  88. package/dist/store/sqlite/work-tasks.js +6 -0
  89. package/dist/store/store.d.ts +6 -0
  90. package/dist/store/store.js +10 -0
  91. package/package.json +4 -2
  92. package/schemas/records-envelope.v1.schema.json +108 -0
@@ -14890,6 +14890,359 @@ export declare const paymentAllocations: import("drizzle-orm/sqlite-core").SQLit
14890
14890
  dialect: 'sqlite';
14891
14891
  isAlias: false;
14892
14892
  }>;
14893
+ /** What a source said about one of its records, as it said it: the layer under the entity an import makes. */
14894
+ export declare const records: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
14895
+ name: "records";
14896
+ schema: undefined;
14897
+ columns: {
14898
+ id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
14899
+ name: string;
14900
+ tableName: "records";
14901
+ dataType: "number int53";
14902
+ data: number;
14903
+ driverParam: number;
14904
+ notNull: true;
14905
+ hasDefault: true;
14906
+ isPrimaryKey: true;
14907
+ isAutoincrement: false;
14908
+ hasRuntimeDefault: false;
14909
+ enumValues: undefined;
14910
+ baseColumn: never;
14911
+ identity: undefined;
14912
+ generated: undefined;
14913
+ }, {}>;
14914
+ accountId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
14915
+ name: string;
14916
+ tableName: "records";
14917
+ dataType: "number int53";
14918
+ data: number;
14919
+ driverParam: number;
14920
+ notNull: true;
14921
+ hasDefault: false;
14922
+ isPrimaryKey: false;
14923
+ isAutoincrement: false;
14924
+ hasRuntimeDefault: false;
14925
+ enumValues: undefined;
14926
+ baseColumn: never;
14927
+ identity: undefined;
14928
+ generated: undefined;
14929
+ }, {}>;
14930
+ type: import("drizzle-orm/sqlite-core").SQLiteColumn<{
14931
+ name: string;
14932
+ tableName: "records";
14933
+ dataType: "string";
14934
+ data: string;
14935
+ driverParam: string;
14936
+ notNull: true;
14937
+ hasDefault: false;
14938
+ isPrimaryKey: false;
14939
+ isAutoincrement: false;
14940
+ hasRuntimeDefault: false;
14941
+ enumValues: [string, ...string[]];
14942
+ baseColumn: never;
14943
+ identity: undefined;
14944
+ generated: undefined;
14945
+ }, {}>;
14946
+ externalId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
14947
+ name: string;
14948
+ tableName: "records";
14949
+ dataType: "string";
14950
+ data: string;
14951
+ driverParam: string;
14952
+ notNull: true;
14953
+ hasDefault: false;
14954
+ isPrimaryKey: false;
14955
+ isAutoincrement: false;
14956
+ hasRuntimeDefault: false;
14957
+ enumValues: [string, ...string[]];
14958
+ baseColumn: never;
14959
+ identity: undefined;
14960
+ generated: undefined;
14961
+ }, {}>;
14962
+ fields: import("drizzle-orm/sqlite-core").SQLiteColumn<{
14963
+ name: string;
14964
+ tableName: "records";
14965
+ dataType: "string";
14966
+ data: string;
14967
+ driverParam: string;
14968
+ notNull: true;
14969
+ hasDefault: false;
14970
+ isPrimaryKey: false;
14971
+ isAutoincrement: false;
14972
+ hasRuntimeDefault: false;
14973
+ enumValues: [string, ...string[]];
14974
+ baseColumn: never;
14975
+ identity: undefined;
14976
+ generated: undefined;
14977
+ }, {}>;
14978
+ revision: import("drizzle-orm/sqlite-core").SQLiteColumn<{
14979
+ name: string;
14980
+ tableName: "records";
14981
+ dataType: "number int53";
14982
+ data: number;
14983
+ driverParam: number;
14984
+ notNull: false;
14985
+ hasDefault: false;
14986
+ isPrimaryKey: false;
14987
+ isAutoincrement: false;
14988
+ hasRuntimeDefault: false;
14989
+ enumValues: undefined;
14990
+ baseColumn: never;
14991
+ identity: undefined;
14992
+ generated: undefined;
14993
+ }, {}>;
14994
+ fingerprint: import("drizzle-orm/sqlite-core").SQLiteColumn<{
14995
+ name: string;
14996
+ tableName: "records";
14997
+ dataType: "string";
14998
+ data: string;
14999
+ driverParam: string;
15000
+ notNull: true;
15001
+ hasDefault: false;
15002
+ isPrimaryKey: false;
15003
+ isAutoincrement: false;
15004
+ hasRuntimeDefault: false;
15005
+ enumValues: [string, ...string[]];
15006
+ baseColumn: never;
15007
+ identity: undefined;
15008
+ generated: undefined;
15009
+ }, {}>;
15010
+ entityType: import("drizzle-orm/sqlite-core").SQLiteColumn<{
15011
+ name: string;
15012
+ tableName: "records";
15013
+ dataType: "string";
15014
+ data: string;
15015
+ driverParam: string;
15016
+ notNull: false;
15017
+ hasDefault: false;
15018
+ isPrimaryKey: false;
15019
+ isAutoincrement: false;
15020
+ hasRuntimeDefault: false;
15021
+ enumValues: [string, ...string[]];
15022
+ baseColumn: never;
15023
+ identity: undefined;
15024
+ generated: undefined;
15025
+ }, {}>;
15026
+ entityId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
15027
+ name: string;
15028
+ tableName: "records";
15029
+ dataType: "number int53";
15030
+ data: number;
15031
+ driverParam: number;
15032
+ notNull: false;
15033
+ hasDefault: false;
15034
+ isPrimaryKey: false;
15035
+ isAutoincrement: false;
15036
+ hasRuntimeDefault: false;
15037
+ enumValues: undefined;
15038
+ baseColumn: never;
15039
+ identity: undefined;
15040
+ generated: undefined;
15041
+ }, {}>;
15042
+ projectedFingerprint: import("drizzle-orm/sqlite-core").SQLiteColumn<{
15043
+ name: string;
15044
+ tableName: "records";
15045
+ dataType: "string";
15046
+ data: string;
15047
+ driverParam: string;
15048
+ notNull: false;
15049
+ hasDefault: false;
15050
+ isPrimaryKey: false;
15051
+ isAutoincrement: false;
15052
+ hasRuntimeDefault: false;
15053
+ enumValues: [string, ...string[]];
15054
+ baseColumn: never;
15055
+ identity: undefined;
15056
+ generated: undefined;
15057
+ }, {}>;
15058
+ batchId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
15059
+ name: string;
15060
+ tableName: "records";
15061
+ dataType: "string";
15062
+ data: string;
15063
+ driverParam: string;
15064
+ notNull: true;
15065
+ hasDefault: false;
15066
+ isPrimaryKey: false;
15067
+ isAutoincrement: false;
15068
+ hasRuntimeDefault: false;
15069
+ enumValues: [string, ...string[]];
15070
+ baseColumn: never;
15071
+ identity: undefined;
15072
+ generated: undefined;
15073
+ }, {}>;
15074
+ createdAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
15075
+ name: string;
15076
+ tableName: "records";
15077
+ dataType: "number int53";
15078
+ data: number;
15079
+ driverParam: number;
15080
+ notNull: true;
15081
+ hasDefault: false;
15082
+ isPrimaryKey: false;
15083
+ isAutoincrement: false;
15084
+ hasRuntimeDefault: false;
15085
+ enumValues: undefined;
15086
+ baseColumn: never;
15087
+ identity: undefined;
15088
+ generated: undefined;
15089
+ }, {}>;
15090
+ updatedAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
15091
+ name: string;
15092
+ tableName: "records";
15093
+ dataType: "number int53";
15094
+ data: number;
15095
+ driverParam: number;
15096
+ notNull: true;
15097
+ hasDefault: false;
15098
+ isPrimaryKey: false;
15099
+ isAutoincrement: false;
15100
+ hasRuntimeDefault: false;
15101
+ enumValues: undefined;
15102
+ baseColumn: never;
15103
+ identity: undefined;
15104
+ generated: undefined;
15105
+ }, {}>;
15106
+ deletedAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
15107
+ name: string;
15108
+ tableName: "records";
15109
+ dataType: "number int53";
15110
+ data: number;
15111
+ driverParam: number;
15112
+ notNull: false;
15113
+ hasDefault: false;
15114
+ isPrimaryKey: false;
15115
+ isAutoincrement: false;
15116
+ hasRuntimeDefault: false;
15117
+ enumValues: undefined;
15118
+ baseColumn: never;
15119
+ identity: undefined;
15120
+ generated: undefined;
15121
+ }, {}>;
15122
+ };
15123
+ dialect: 'sqlite';
15124
+ isAlias: false;
15125
+ }>;
15126
+ export declare const recordRelations: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
15127
+ name: "record_relations";
15128
+ schema: undefined;
15129
+ columns: {
15130
+ id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
15131
+ name: string;
15132
+ tableName: "record_relations";
15133
+ dataType: "number int53";
15134
+ data: number;
15135
+ driverParam: number;
15136
+ notNull: true;
15137
+ hasDefault: true;
15138
+ isPrimaryKey: true;
15139
+ isAutoincrement: false;
15140
+ hasRuntimeDefault: false;
15141
+ enumValues: undefined;
15142
+ baseColumn: never;
15143
+ identity: undefined;
15144
+ generated: undefined;
15145
+ }, {}>;
15146
+ recordId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
15147
+ name: string;
15148
+ tableName: "record_relations";
15149
+ dataType: "number int53";
15150
+ data: number;
15151
+ driverParam: number;
15152
+ notNull: true;
15153
+ hasDefault: false;
15154
+ isPrimaryKey: false;
15155
+ isAutoincrement: false;
15156
+ hasRuntimeDefault: false;
15157
+ enumValues: undefined;
15158
+ baseColumn: never;
15159
+ identity: undefined;
15160
+ generated: undefined;
15161
+ }, {}>;
15162
+ role: import("drizzle-orm/sqlite-core").SQLiteColumn<{
15163
+ name: string;
15164
+ tableName: "record_relations";
15165
+ dataType: "string";
15166
+ data: string;
15167
+ driverParam: string;
15168
+ notNull: true;
15169
+ hasDefault: false;
15170
+ isPrimaryKey: false;
15171
+ isAutoincrement: false;
15172
+ hasRuntimeDefault: false;
15173
+ enumValues: [string, ...string[]];
15174
+ baseColumn: never;
15175
+ identity: undefined;
15176
+ generated: undefined;
15177
+ }, {}>;
15178
+ targetType: import("drizzle-orm/sqlite-core").SQLiteColumn<{
15179
+ name: string;
15180
+ tableName: "record_relations";
15181
+ dataType: "string";
15182
+ data: string;
15183
+ driverParam: string;
15184
+ notNull: true;
15185
+ hasDefault: false;
15186
+ isPrimaryKey: false;
15187
+ isAutoincrement: false;
15188
+ hasRuntimeDefault: false;
15189
+ enumValues: [string, ...string[]];
15190
+ baseColumn: never;
15191
+ identity: undefined;
15192
+ generated: undefined;
15193
+ }, {}>;
15194
+ targetExternalId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
15195
+ name: string;
15196
+ tableName: "record_relations";
15197
+ dataType: "string";
15198
+ data: string;
15199
+ driverParam: string;
15200
+ notNull: true;
15201
+ hasDefault: false;
15202
+ isPrimaryKey: false;
15203
+ isAutoincrement: false;
15204
+ hasRuntimeDefault: false;
15205
+ enumValues: [string, ...string[]];
15206
+ baseColumn: never;
15207
+ identity: undefined;
15208
+ generated: undefined;
15209
+ }, {}>;
15210
+ targetId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
15211
+ name: string;
15212
+ tableName: "record_relations";
15213
+ dataType: "number int53";
15214
+ data: number;
15215
+ driverParam: number;
15216
+ notNull: false;
15217
+ hasDefault: false;
15218
+ isPrimaryKey: false;
15219
+ isAutoincrement: false;
15220
+ hasRuntimeDefault: false;
15221
+ enumValues: undefined;
15222
+ baseColumn: never;
15223
+ identity: undefined;
15224
+ generated: undefined;
15225
+ }, {}>;
15226
+ createdAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
15227
+ name: string;
15228
+ tableName: "record_relations";
15229
+ dataType: "number int53";
15230
+ data: number;
15231
+ driverParam: number;
15232
+ notNull: true;
15233
+ hasDefault: false;
15234
+ isPrimaryKey: false;
15235
+ isAutoincrement: false;
15236
+ hasRuntimeDefault: false;
15237
+ enumValues: undefined;
15238
+ baseColumn: never;
15239
+ identity: undefined;
15240
+ generated: undefined;
15241
+ }, {}>;
15242
+ };
15243
+ dialect: 'sqlite';
15244
+ isAlias: false;
15245
+ }>;
14893
15246
  export declare const proposedActions: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
14894
15247
  name: "proposed_actions";
14895
15248
  schema: undefined;
@@ -1492,6 +1492,43 @@ export const paymentAllocations = sqliteTable("payment_allocations", {
1492
1492
  index("payment_allocations_by_invoice_id").on(table.invoiceId),
1493
1493
  index("payment_allocations_by_author_type_author_id").on(table.authorType, table.authorId),
1494
1494
  ]);
1495
+ /** What a source said about one of its records, as it said it: the layer under the entity an import makes. */
1496
+ export const records = sqliteTable("records", {
1497
+ id: integer("id").primaryKey(),
1498
+ accountId: integer("account_id")
1499
+ .notNull()
1500
+ .references(() => accounts.id),
1501
+ type: text("type").notNull(),
1502
+ externalId: text("external_id").notNull(),
1503
+ fields: text("fields").notNull(),
1504
+ revision: integer("revision"),
1505
+ fingerprint: text("fingerprint").notNull(),
1506
+ entityType: text("entity_type"),
1507
+ entityId: integer("entity_id"),
1508
+ projectedFingerprint: text("projected_fingerprint"),
1509
+ batchId: text("batch_id").notNull(),
1510
+ createdAt: integer("created_at").notNull(),
1511
+ updatedAt: integer("updated_at").notNull(),
1512
+ deletedAt: integer("deleted_at"),
1513
+ }, (table) => [
1514
+ unique().on(table.accountId, table.type, table.externalId),
1515
+ index("records_by_entity_type_entity_id").on(table.entityType, table.entityId),
1516
+ ]);
1517
+ export const recordRelations = sqliteTable("record_relations", {
1518
+ id: integer("id").primaryKey(),
1519
+ recordId: integer("record_id")
1520
+ .notNull()
1521
+ .references(() => records.id),
1522
+ role: text("role").notNull(),
1523
+ targetType: text("target_type").notNull(),
1524
+ targetExternalId: text("target_external_id").notNull(),
1525
+ targetId: integer("target_id").references(() => records.id),
1526
+ createdAt: integer("created_at").notNull(),
1527
+ }, (table) => [
1528
+ unique().on(table.recordId, table.role, table.targetType, table.targetExternalId),
1529
+ index("record_relations_by_target_type_target_external_id").on(table.targetType, table.targetExternalId),
1530
+ index("record_relations_by_target_id").on(table.targetId),
1531
+ ]);
1495
1532
  export const proposedActions = sqliteTable("proposed_actions", {
1496
1533
  id: integer("id").primaryKey(),
1497
1534
  kind: text("kind").notNull(),
@@ -36,4 +36,6 @@ export interface StoreTaskStore extends Omit<Required<TaskStore>, "reviewDuplica
36
36
  closeSuggestion: CloseSuggestion | null;
37
37
  }[]>;
38
38
  }
39
+ /** The inbox project of a task account (`telegram:100`), made the first time `create` asks for it. */
40
+ export declare const inboxProject: ({ database, now }: Pick<StoreContext, "database" | "now">, account: string, create: boolean) => number | undefined;
39
41
  export declare const taskStoreOver: (context: StoreContext) => StoreTaskStore;
@@ -18,32 +18,34 @@ export { inboxKey, linkInbox, taskAccountOf } from "./task-keys.js";
18
18
  export { taskIdOf, taskRowOf } from "./things.js";
19
19
  const COLUMNS = "t.id AS row_id, t.package_id, t.source_locator, t.source_kind, t.source_group, t.type, t.status, t.close_reason, t.source, t.created_at, t.due_at, t.closed_at, " +
20
20
  "t.closed_by_type, t.closed_by_id, t.key, t.category, t.claimed_by, t.claimed_until, p.name AS account";
21
+ /** The inbox project of a task account (`telegram:100`), made the first time `create` asks for it. */
22
+ export const inboxProject = ({ database, now }, account, create) => {
23
+ const key = inboxKey(account);
24
+ const found = database.prepare("SELECT id FROM projects WHERE key = ?").get(key);
25
+ if (!create)
26
+ return found ? Number(found.id) : undefined;
27
+ const [provider, external] = [account.slice(0, account.indexOf(":")), account.slice(account.indexOf(":") + 1)];
28
+ const owning = database
29
+ .prepare("SELECT id FROM accounts WHERE provider = ? AND external_id = ?")
30
+ .get(provider, external);
31
+ const accountId = owning ? Number(owning.id) : null;
32
+ // A task can arrive before its messenger saved the account; the project learns it on a later task.
33
+ if (found) {
34
+ if (accountId !== null)
35
+ database
36
+ .prepare("UPDATE projects SET account_id = ? WHERE id = ? AND account_id IS NULL")
37
+ .run(accountId, Number(found.id));
38
+ return Number(found.id);
39
+ }
40
+ const at = now();
41
+ return Number(database
42
+ .prepare("INSERT INTO projects (key, name, name_folded, description, type, account_id, scope, tasks_count, status, created_at, updated_at) " +
43
+ "VALUES (?, ?, ?, ?, 'personal', ?, 'personal', 0, 'active', ?, ?) RETURNING id")
44
+ .get(key, account, folded(account), `What waits on the owner in ${account}`, accountId, at, at)?.id);
45
+ };
21
46
  export const taskStoreOver = (context) => {
22
47
  const { database, now } = context;
23
- const inbox = (account, create) => {
24
- const key = inboxKey(account);
25
- const found = database.prepare("SELECT id FROM projects WHERE key = ?").get(key);
26
- if (!create)
27
- return found ? Number(found.id) : undefined;
28
- const [provider, external] = [account.slice(0, account.indexOf(":")), account.slice(account.indexOf(":") + 1)];
29
- const owning = database
30
- .prepare("SELECT id FROM accounts WHERE provider = ? AND external_id = ?")
31
- .get(provider, external);
32
- const accountId = owning ? Number(owning.id) : null;
33
- // A task can arrive before its messenger saved the account; the project learns it on a later task.
34
- if (found) {
35
- if (accountId !== null)
36
- database
37
- .prepare("UPDATE projects SET account_id = ? WHERE id = ? AND account_id IS NULL")
38
- .run(accountId, Number(found.id));
39
- return Number(found.id);
40
- }
41
- const at = now();
42
- return Number(database
43
- .prepare("INSERT INTO projects (key, name, name_folded, description, type, account_id, scope, tasks_count, status, created_at, updated_at) " +
44
- "VALUES (?, ?, ?, ?, 'personal', ?, 'personal', 0, 'active', ?, ?) RETURNING id")
45
- .get(key, account, folded(account), `What waits on the owner in ${account}`, accountId, at, at)?.id);
46
- };
48
+ const inbox = (account, create) => inboxProject(context, account, create);
47
49
  // A task made here has no package id and may be a type the package does not know; the package never sees it.
48
50
  const select = (where) => database.prepare(`SELECT ${COLUMNS} FROM tasks t JOIN projects p ON p.id = t.project_id WHERE t.package_id IS NOT NULL AND ${where}`);
49
51
  const toTask = (row) => {
@@ -0,0 +1,8 @@
1
+ import type { StoreContext } from "./open.js";
2
+ /** Set by store version 48 and deleted once the purge ran. */
3
+ export declare const TEST_ACCOUNTS_TO_PURGE = "test_accounts_to_purge";
4
+ /**
5
+ * Removes every account of the test provider, as `cache clear` removes one. A failure keeps the key for the next open
6
+ * and only warns: a leftover test account must never stop the owner's store from opening.
7
+ */
8
+ export declare const purgeTestAccounts: (context: StoreContext, warn: (line: string) => void) => number;
@@ -0,0 +1,31 @@
1
+ import { purgeAccount } from "./accounts.js";
2
+ import { write } from "./transaction.js";
3
+ /** Set by store version 48 and deleted once the purge ran. */
4
+ export const TEST_ACCOUNTS_TO_PURGE = "test_accounts_to_purge";
5
+ /** The fake messenger of `src/testing/shared-program.ts`; no tool writes it. */
6
+ const TEST_PROVIDER = "chat";
7
+ /**
8
+ * Removes every account of the test provider, as `cache clear` removes one. A failure keeps the key for the next open
9
+ * and only warns: a leftover test account must never stop the owner's store from opening.
10
+ */
11
+ export const purgeTestAccounts = (context, warn) => {
12
+ const { database } = context;
13
+ if (!database.prepare("SELECT 1 AS found FROM store_settings WHERE key = ?").get(TEST_ACCOUNTS_TO_PURGE))
14
+ return 0;
15
+ try {
16
+ return write(database, () => {
17
+ const pks = database
18
+ .prepare("SELECT id FROM accounts WHERE provider = ? ORDER BY id")
19
+ .all(TEST_PROVIDER)
20
+ .map((row) => Number(row.id));
21
+ for (const pk of pks)
22
+ purgeAccount(context, pk);
23
+ database.prepare("DELETE FROM store_settings WHERE key = ?").run(TEST_ACCOUNTS_TO_PURGE);
24
+ return pks.length;
25
+ });
26
+ }
27
+ catch (error) {
28
+ warn(`could not remove the test accounts from the store; the next open tries again: ${String(error)}`);
29
+ return 0;
30
+ }
31
+ };
@@ -232,6 +232,7 @@ export declare const checkRevision: (row: Row, expected: number | undefined) =>
232
232
  type WorkTaskOperations = Omit<WorkTasks, "create" | "assign"> & {
233
233
  create(input: NewWorkTask, by: Author): TaskDetails;
234
234
  assign(id: string, assignment: TaskAssignment, by: Author, check?: RevisionCheck): TaskDetails;
235
+ editNow(id: string, fields: TaskFields, by: Author): TaskDetails;
235
236
  };
236
237
  export declare const workTaskOperationsOver: (context: StoreContext) => WorkTaskOperations;
237
238
  export declare const workTasksOver: (context: StoreContext) => WorkTasks;
@@ -396,6 +396,12 @@ export const workTaskOperationsOver = (context) => {
396
396
  });
397
397
  return details(task);
398
398
  },
399
+ /** `edit` inside the caller's write, so a decision that edits a task rolls back with it. */
400
+ editNow: (id, fields, by) => {
401
+ const task = required(id);
402
+ write(database, () => edit(task, fields, authorActor(context, by).actor));
403
+ return details(task);
404
+ },
399
405
  move: async (id, move, by, check = {}) => {
400
406
  const task = required(id);
401
407
  return write(database, () => {
@@ -9,6 +9,7 @@ import { type ConversationsStore } from "./conversations.js";
9
9
  import { type CountersStore } from "./counters.js";
10
10
  import { type DecisionPolicy } from "./decisions.js";
11
11
  import type { EvidenceFindingsStore } from "./evidence-findings.js";
12
+ import type { MailFindingsStore } from "./mail-findings.js";
12
13
  import type { MeetingFindingsStore } from "./meeting-findings.js";
13
14
  import { type MentionsStore } from "./mentions.js";
14
15
  import { type MessagesStore } from "./messages.js";
@@ -35,6 +36,7 @@ import { type SourceMentionStore } from "./sqlite/mention-sources.js";
35
36
  import { type NotesStore } from "./sqlite/notes.js";
36
37
  import { type StoreOptions } from "./sqlite/open-store.js";
37
38
  import { type ProposedActionsStore } from "./sqlite/proposed-actions.js";
39
+ import { type RecordStore } from "./sqlite/records.js";
38
40
  import { type StoreTaskStore } from "./sqlite/tasks.js";
39
41
  import { type SyncStore } from "./sync.js";
40
42
  import { type TagsStore } from "./tags.js";
@@ -93,11 +95,15 @@ export interface MessageStore {
93
95
  readonly meetingFindings: MeetingFindingsStore;
94
96
  /** Cited facts and follow-ups about one project from stored messages, mail and documents, for review. */
95
97
  readonly evidenceFindings: EvidenceFindingsStore;
98
+ /** What an agent read in new mail, cited and staged per mailbox; only the owner decides it. */
99
+ readonly mailFindings: MailFindingsStore;
96
100
  /** What any ref names, a page of them at a time: read once per page, never once per row. */
97
101
  readonly refs: RefsStore;
98
102
  readonly facts: FactsStore;
99
103
  /** Invoices, payments and their allocations, in exact minor units; an agent's or an import's wait for the owner. */
100
104
  readonly finance: FinanceStore;
105
+ /** What each import said, by the source's identity; `ingest` (services) is the way in. */
106
+ readonly records: RecordStore;
101
107
  /** What agents concluded: summaries, digests, facts, preferences, each with evidence and a scope. */
102
108
  readonly memories: MemoriesStore;
103
109
  /** What an agent wants done outside the store, waiting for the owner's approval. */
@@ -28,6 +28,7 @@ import { financeStoreOver } from "./sqlite/finance.js";
28
28
  import { involvementStoreOver } from "./sqlite/involvements.js";
29
29
  import { knowledgeStoreOver } from "./sqlite/knowledge.js";
30
30
  import { logPruner } from "./sqlite/log-pruning.js";
31
+ import { mailFindingsStoreOver } from "./sqlite/mail-findings.js";
31
32
  import { meetingFindingsStoreOver } from "./sqlite/meeting-findings.js";
32
33
  import { meetingVectorsOver } from "./sqlite/meeting-vectors.js";
33
34
  import { meetingStoreOver } from "./sqlite/meetings.js";
@@ -38,6 +39,7 @@ import { notesStoreOver } from "./sqlite/notes.js";
38
39
  import { openStoreContext } from "./sqlite/open-store.js";
39
40
  import { projectAnnotationStoreOver } from "./sqlite/project-transfer/store.js";
40
41
  import { proposedActionsStoreOver } from "./sqlite/proposed-actions.js";
42
+ import { recordStoreOver } from "./sqlite/records.js";
41
43
  import { refSummariesOf } from "./sqlite/ref-summaries.js";
42
44
  import * as stems from "./sqlite/stems.js";
43
45
  import { taskStoreOver } from "./sqlite/tasks.js";
@@ -107,11 +109,13 @@ const storeOver = (context) => {
107
109
  const calendar = once(() => ({ ...eventStoreOver(context), ...eventSearchOver(context) }));
108
110
  const meetingFindings = once(() => meetingFindingsStoreOver(context));
109
111
  const evidenceFindings = once(() => evidenceFindingsStoreOver(context));
112
+ const mailFindings = once(() => mailFindingsStoreOver(context));
110
113
  const refs = {
111
114
  summaries: async (texts, options) => refSummariesOf(context.database, texts, options),
112
115
  };
113
116
  const facts = once(() => factsStoreOver(context));
114
117
  const finance = once(() => financeStoreOver(context));
118
+ const records = once(() => recordStoreOver(context));
115
119
  const memories = once(() => memoriesStoreOver(context));
116
120
  const proposedActions = once(() => proposedActionsStoreOver(context));
117
121
  const agentActions = once(() => agentActionsStoreOver(context, pruneLogsWhenDue));
@@ -209,12 +213,18 @@ const storeOver = (context) => {
209
213
  get evidenceFindings() {
210
214
  return evidenceFindings();
211
215
  },
216
+ get mailFindings() {
217
+ return mailFindings();
218
+ },
212
219
  get facts() {
213
220
  return facts();
214
221
  },
215
222
  get finance() {
216
223
  return finance();
217
224
  },
225
+ get records() {
226
+ return records();
227
+ },
218
228
  get memories() {
219
229
  return memories();
220
230
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wirecat/cli-core",
3
- "version": "0.558.0",
3
+ "version": "0.560.0",
4
4
  "description": "The messenger-neutral half of a messaging CLI: domain model, message locators, rendering, name resolution, the SQLite seam, the command skeleton and shared read commands, the send guard, run records and the message store",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Viacheslav Ptsarev",
@@ -25,9 +25,11 @@
25
25
  "CHANGELOG.md",
26
26
  "LICENSE",
27
27
  "THIRD_PARTY_NOTICES",
28
- "docs/search/recipes.json"
28
+ "docs/search/recipes.json",
29
+ "schemas"
29
30
  ],
30
31
  "exports": {
32
+ "./schemas/records-envelope.v1.schema.json": "./schemas/records-envelope.v1.schema.json",
31
33
  "./documents": {
32
34
  "types": "./dist/documents.d.ts",
33
35
  "default": "./dist/documents.js"