@unson/brainbase-mcp 0.44.0 → 0.44.1

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 (72) hide show
  1. package/contracts/canonical-task/operation-schema.sql +58 -0
  2. package/contracts/canonical-task/search-indexes.sql +10 -0
  3. package/contracts/canonical-task/store-schema.sql +77 -0
  4. package/dist/automation-run.d.ts +213 -0
  5. package/dist/automation-run.js +479 -0
  6. package/dist/canonical-task-operations.d.ts +205 -0
  7. package/dist/canonical-task-operations.js +700 -0
  8. package/dist/canonical-task-postgres.d.ts +139 -0
  9. package/dist/canonical-task-postgres.js +554 -0
  10. package/dist/canonical-task-service.d.ts +13 -0
  11. package/dist/canonical-task-service.js +55 -3
  12. package/dist/canonical-task-store-config.d.ts +31 -0
  13. package/dist/canonical-task-store-config.js +53 -0
  14. package/dist/config-parser.d.ts +298 -0
  15. package/dist/config-parser.js +593 -0
  16. package/dist/connected-onboarding.d.ts +57 -0
  17. package/dist/connected-onboarding.js +37 -0
  18. package/dist/durable-wait-http.d.ts +3 -1
  19. package/dist/durable-wait-http.js +73 -6
  20. package/dist/durable-waits.d.ts +93 -3
  21. package/dist/durable-waits.js +320 -8
  22. package/dist/honcho.d.ts +25 -0
  23. package/dist/honcho.js +81 -0
  24. package/dist/judgment-event-adapter.d.ts +72 -0
  25. package/dist/judgment-event-adapter.js +114 -0
  26. package/dist/judgment-event-outbox.d.ts +182 -0
  27. package/dist/judgment-event-outbox.js +568 -0
  28. package/dist/judgment-execution-outcome.d.ts +46 -0
  29. package/dist/judgment-execution-outcome.js +149 -0
  30. package/dist/judgment-host.d.ts +18 -7
  31. package/dist/judgment-host.js +82 -34
  32. package/dist/judgment-lifecycle-core.d.ts +198 -0
  33. package/dist/judgment-lifecycle-core.js +464 -0
  34. package/dist/judgment-node-evidence.d.ts +57 -0
  35. package/dist/judgment-node-evidence.js +297 -0
  36. package/dist/judgment-runtime-resolution.d.ts +264 -0
  37. package/dist/judgment-runtime-resolution.js +1248 -0
  38. package/dist/judgment-runtime-resolution.public.d.ts +255 -0
  39. package/dist/knowledge-event.d.ts +28 -0
  40. package/dist/knowledge-event.js +114 -0
  41. package/dist/mcp-runtime.d.ts +75 -0
  42. package/dist/mcp-runtime.js +188 -0
  43. package/dist/meeting-automation-runtime.d.ts +102 -0
  44. package/dist/meeting-automation-runtime.js +249 -0
  45. package/dist/meeting-automation.d.ts +155 -0
  46. package/dist/meeting-automation.js +341 -0
  47. package/dist/meeting-minutes-context-receipt.d.ts +91 -0
  48. package/dist/meeting-minutes-context-receipt.js +280 -0
  49. package/dist/meeting-source-sync.d.ts +89 -0
  50. package/dist/meeting-source-sync.js +230 -0
  51. package/dist/mesh.d.ts +58 -0
  52. package/dist/mesh.js +134 -0
  53. package/dist/onboarding-runtime.d.ts +47 -0
  54. package/dist/onboarding-runtime.js +4719 -0
  55. package/dist/routine-cycle.d.ts +51 -0
  56. package/dist/routine-cycle.js +153 -0
  57. package/dist/routine-liveness.d.ts +49 -0
  58. package/dist/routine-liveness.js +227 -0
  59. package/dist/routine-runtime.d.ts +101 -0
  60. package/dist/routine-runtime.js +237 -0
  61. package/dist/routines.d.ts +3 -0
  62. package/dist/routines.js +3 -0
  63. package/dist/run-receipt.d.ts +40 -0
  64. package/dist/run-receipt.js +635 -0
  65. package/dist/runtime-host.d.ts +64 -0
  66. package/dist/runtime-host.js +70 -0
  67. package/dist/world-work.d.ts +16 -0
  68. package/package.json +115 -3
  69. package/ui/objective-editor.js +47 -11
  70. package/ui/world/world-district.js +18 -3
  71. package/ui/world/world-placement.js +13 -0
  72. package/ui/world/world-work-rail.js +7 -1
@@ -1,5 +1,5 @@
1
1
  import { type IncomingMessage, type Server, type ServerResponse } from 'node:http';
2
- import { type DurableWaitStore } from './durable-waits.js';
2
+ import { type DurableWaitDueCandidatesInput, type DurableWaitStore } from './durable-waits.js';
3
3
  /** Version of the HTTP boundary. The store version is returned separately. */
4
4
  export declare const DURABLE_WAIT_HTTP_VERSION: "durable-wait-http.v1";
5
5
  type MaybePromise<T> = T | Promise<T>;
@@ -8,6 +8,8 @@ export interface TrustedDurableWaitRequestContext {
8
8
  readonly tenantId: string;
9
9
  readonly principal: string;
10
10
  readonly scopeId: string;
11
+ /** Required for tenant-tagged waits and due discovery; resolved by the host, never from the request. */
12
+ readonly scopeType?: DurableWaitDueCandidatesInput['owner_scope_type'];
11
13
  /** A non-empty value means that the host already verified the mutation origin. */
12
14
  readonly verifiedMutationOrigin?: string;
13
15
  }
@@ -96,8 +96,15 @@ const premiseChangedSchema = identitySchema.extend({
96
96
  const effectUnknownSchema = identitySchema.extend({
97
97
  wait_id: boundedText,
98
98
  reason: boundedText,
99
+ external_operation_id: boundedText.optional(),
99
100
  responsible: responsibleSchema.optional(),
100
101
  }).strict();
102
+ const reconcileExternalEffectSchema = identitySchema.extend({
103
+ wait_id: boundedText,
104
+ request_id: boundedText,
105
+ external_operation_id: boundedText,
106
+ evidence_ref: boundedText,
107
+ }).strict();
101
108
  class HttpInputError extends Error {
102
109
  constructor(message) {
103
110
  super(message);
@@ -209,6 +216,8 @@ function normalizePath(path) {
209
216
  }
210
217
  function matchRoute(path, basePath) {
211
218
  const normalized = normalizePath(path);
219
+ if (normalized === `${basePath}:due`)
220
+ return { operation: 'due' };
212
221
  if (normalized === basePath)
213
222
  return { operation: null };
214
223
  const prefix = `${basePath}/`;
@@ -216,7 +225,7 @@ function matchRoute(path, basePath) {
216
225
  return null;
217
226
  const suffix = normalized.slice(prefix.length);
218
227
  const operationNames = [
219
- 'create', 'claim', 'resume', 'handoff', 'premise-changed', 'effect-unknown',
228
+ 'create', 'claim', 'resume', 'handoff', 'premise-changed', 'effect-unknown', 'reconcile-external-effect',
220
229
  ];
221
230
  if (operationNames.includes(suffix))
222
231
  return { operation: suffix };
@@ -273,8 +282,11 @@ function bindTrustedIdentity(body, context) {
273
282
  return input;
274
283
  }
275
284
  function assertOwnerScope(result, context) {
276
- if (!isRecord(result) || !isRecord(result.owner_scope) || result.owner_scope.id !== context.scopeId) {
277
- throw new DurableWaitError('unauthorized', 'Durable wait scope does not match the trusted request context');
285
+ if (!isRecord(result) || !isRecord(result.owner_scope)
286
+ || result.owner_scope.id !== context.scopeId
287
+ || (result.tenant_id !== undefined
288
+ && (result.tenant_id !== context.tenantId || result.owner_scope.type !== context.scopeType))) {
289
+ throw new DurableWaitError('unauthorized', 'Durable wait tenant or scope type and ID do not match the trusted request context');
278
290
  }
279
291
  }
280
292
  function serviceError(error) {
@@ -305,7 +317,30 @@ function writeError(response, status, code, message) {
305
317
  });
306
318
  }
307
319
  function methodAllowed(operation, method) {
308
- return operation === 'read' ? method === 'GET' : operation !== null && method === 'POST';
320
+ return operation === 'read' || operation === 'due' ? method === 'GET' : operation !== null && method === 'POST';
321
+ }
322
+ function parseDueQuery(request) {
323
+ let url;
324
+ try {
325
+ url = new URL(request.url ?? '/', 'http://localhost');
326
+ }
327
+ catch {
328
+ throw new HttpInputError('Request URL is invalid');
329
+ }
330
+ for (const key of url.searchParams.keys()) {
331
+ if ((key !== 'limit' && key !== 'cursor') || url.searchParams.getAll(key).length !== 1) {
332
+ throw new HttpInputError('Due candidate query is invalid');
333
+ }
334
+ }
335
+ const rawLimit = url.searchParams.get('limit');
336
+ if (rawLimit !== null && !/^(?:[1-9]|[1-9][0-9]|100)$/u.test(rawLimit)) {
337
+ throw new HttpInputError('limit must be an integer from 1 to 100');
338
+ }
339
+ const cursor = url.searchParams.get('cursor');
340
+ return {
341
+ ...(rawLimit === null ? {} : { limit: Number(rawLimit) }),
342
+ ...(cursor === null ? {} : { cursor })
343
+ };
309
344
  }
310
345
  async function verifyMutationRequest(options, request, context) {
311
346
  if (typeof context.verifiedMutationOrigin === 'string' && context.verifiedMutationOrigin.trim().length > 0)
@@ -339,12 +374,14 @@ function parseBody(operation, body, context) {
339
374
  case 'handoff': return handoffSchema.safeParse(bound);
340
375
  case 'premise-changed': return premiseChangedSchema.safeParse(bound);
341
376
  case 'effect-unknown': return effectUnknownSchema.safeParse(bound);
377
+ case 'reconcile-external-effect': return reconcileExternalEffectSchema.safeParse(bound);
342
378
  }
343
379
  })();
344
380
  if (!parsed.success)
345
381
  throw new HttpInputError(parsed.error.issues[0]?.message ?? 'Request body is invalid');
346
382
  const value = parsed.data;
347
- if ('owner_scope' in value && isRecord(value.owner_scope) && value.owner_scope.id !== context.scopeId) {
383
+ if ('owner_scope' in value && isRecord(value.owner_scope)
384
+ && (value.owner_scope.id !== context.scopeId || value.owner_scope.type !== context.scopeType)) {
348
385
  throw new HttpInputError('owner_scope does not match the trusted request context');
349
386
  }
350
387
  const { tenantId: _tenantId, scopeId: _scopeId, ...storeInput } = value;
@@ -396,6 +433,32 @@ export function createDurableWaitHttpHandler(options) {
396
433
  }
397
434
  return true;
398
435
  }
436
+ if (route.operation === 'due') {
437
+ try {
438
+ if (!context.scopeType || !['personal', 'project', 'organization'].includes(context.scopeType)) {
439
+ throw new HttpInputError('Trusted scope type is required for due discovery');
440
+ }
441
+ const query = parseDueQuery(request);
442
+ const store = await options.storeFactory(context);
443
+ const result = await store.listDueCandidates({
444
+ tenant_id: context.tenantId,
445
+ principal: context.principal,
446
+ owner_scope_type: context.scopeType,
447
+ owner_scope_id: context.scopeId,
448
+ ...query,
449
+ });
450
+ writeJson(response, 200, success(context, route.operation, result));
451
+ }
452
+ catch (error) {
453
+ if (error instanceof HttpInputError)
454
+ writeError(response, 400, 'invalid_request', error.message);
455
+ else {
456
+ const failure = serviceError(error);
457
+ writeError(response, failure.status, failure.code, failure.message);
458
+ }
459
+ }
460
+ return true;
461
+ }
399
462
  let body;
400
463
  try {
401
464
  body = await readJsonBody(request, bodyLimitBytes);
@@ -434,7 +497,7 @@ export function createDurableWaitHttpHandler(options) {
434
497
  let result;
435
498
  switch (route.operation) {
436
499
  case 'create':
437
- result = await store.create(parsed);
500
+ result = await store.create({ ...parsed, tenant_id: context.tenantId });
438
501
  assertOwnerScope(result, context);
439
502
  break;
440
503
  case 'claim': {
@@ -457,6 +520,10 @@ export function createDurableWaitHttpHandler(options) {
457
520
  result = await store.markEffectUnknown(parsed);
458
521
  assertOwnerScope(result, context);
459
522
  break;
523
+ case 'reconcile-external-effect':
524
+ result = await store.reconcileExternalEffect(parsed);
525
+ assertOwnerScope(result, context);
526
+ break;
460
527
  }
461
528
  writeJson(response, 200, success(context, route.operation, result));
462
529
  }
@@ -6,7 +6,7 @@ import type { FoundationAcl } from './ontology-foundation.js';
6
6
  export declare const DURABLE_WAIT_VERSION: "durable-wait.v1";
7
7
  export declare const DURABLE_WAIT_SIDECAR_PATH: "durable-waits/ledger.json";
8
8
  export declare const DURABLE_WAIT_LEDGER_VERSION: "durable-wait.v1";
9
- export type DurableWaitState = 'waiting' | 'claimed' | 'resumed' | 'handoff_required' | 'reconciliation_wait' | 'failed' | 'cancelled';
9
+ export type DurableWaitState = 'waiting' | 'claimed' | 'resumed' | 'handoff_required' | 'reconciliation_wait' | 'effect_confirmed' | 'failed' | 'cancelled';
10
10
  export type DurableWaitTrigger = 'event' | 'timer' | 'manual';
11
11
  export type DurableWaitResumeMethod = 'resume_run' | 'new_problem' | 'reconcile_external_effect' | 'manual_review';
12
12
  export type DurableWaitFailurePolicy = 'handoff' | 'new_problem' | 'reconciliation_wait' | 'fail';
@@ -62,7 +62,7 @@ export interface DurableWaitResumeReceipt {
62
62
  readonly run_ref: DurableWaitRunReference;
63
63
  readonly recorded_at: string;
64
64
  }
65
- export type DurableWaitHistoryAction = 'create' | 'claim' | 'handoff' | 'premise_changed' | 'effect_unknown' | 'resume';
65
+ export type DurableWaitHistoryAction = 'create' | 'claim' | 'handoff' | 'premise_changed' | 'effect_unknown' | 'effect_reconciled' | 'resume';
66
66
  export interface DurableWaitHistoryEntry {
67
67
  readonly action: DurableWaitHistoryAction;
68
68
  readonly occurred_at: string;
@@ -76,10 +76,28 @@ export interface DurableWaitReconciliation {
76
76
  readonly reason: string;
77
77
  readonly recorded_at: string;
78
78
  readonly responsible: DurableWaitResponsible;
79
+ /** Absent only in legacy records, which cannot be released by reconciliation. */
80
+ readonly external_operation_id?: string;
81
+ readonly claim_id?: string;
82
+ /** Only a trusted execution-intent lookup can set this to verified. */
83
+ readonly binding_status?: 'verified' | 'unverified';
84
+ }
85
+ export type DurableWaitExternalEffectOutcome = 'performed' | 'not_performed' | 'unknown';
86
+ export interface DurableWaitReconciliationReceipt {
87
+ readonly request_id: string;
88
+ readonly external_operation_id: string;
89
+ readonly evidence_ref: string;
90
+ readonly outcome: DurableWaitExternalEffectOutcome;
91
+ readonly principal: string;
92
+ readonly recorded_at: string;
93
+ readonly previous_claim_request_id?: string;
94
+ readonly claim_id?: string;
79
95
  }
80
96
  export interface DurableWaitRecord {
81
97
  readonly wait_id: string;
82
98
  readonly version: typeof DURABLE_WAIT_VERSION;
99
+ /** Absent on legacy records; due enumeration never infers a tenant for them. */
100
+ readonly tenant_id?: string;
83
101
  readonly owner_scope: JudgmentProblemScope;
84
102
  readonly read_policy: FoundationAcl;
85
103
  readonly problem_snapshot: DurableWaitProblemReference;
@@ -96,10 +114,13 @@ export interface DurableWaitRecord {
96
114
  readonly resume_receipt?: DurableWaitResumeReceipt;
97
115
  readonly next_problem?: DurableWaitProblemReference;
98
116
  readonly reconciliation?: DurableWaitReconciliation;
117
+ readonly reconciliation_receipts?: readonly DurableWaitReconciliationReceipt[];
99
118
  readonly history: readonly DurableWaitHistoryEntry[];
100
119
  }
101
120
  export interface DurableWaitCreateInput {
102
121
  readonly wait_id?: string;
122
+ /** Host-authenticated tenant; callers must not copy this from an untrusted body. */
123
+ readonly tenant_id?: string;
103
124
  readonly principal: string;
104
125
  readonly owner_scope: JudgmentProblemScope;
105
126
  readonly read_policy: FoundationAcl;
@@ -118,6 +139,22 @@ export interface DurableWaitReadInput {
118
139
  readonly wait_id: string;
119
140
  readonly principal: string;
120
141
  }
142
+ export interface DurableWaitDueCandidatesInput {
143
+ readonly tenant_id: string;
144
+ readonly principal: string;
145
+ readonly owner_scope_type: JudgmentProblemScope['type'];
146
+ readonly owner_scope_id: string;
147
+ readonly limit?: number;
148
+ readonly cursor?: string;
149
+ }
150
+ export interface DurableWaitDueCandidate {
151
+ readonly wait_id: string;
152
+ readonly due_at: string;
153
+ }
154
+ export interface DurableWaitDueCandidatesPage {
155
+ readonly candidates: readonly DurableWaitDueCandidate[];
156
+ readonly next_cursor?: string;
157
+ }
121
158
  export interface DurableWaitClaimInput extends DurableWaitReadInput {
122
159
  /** Binds the returned lease/token to this particular claim attempt. */
123
160
  readonly request_id: string;
@@ -151,8 +188,52 @@ export interface DurableWaitPremiseChangedInput extends DurableWaitReadInput {
151
188
  }
152
189
  export interface DurableWaitEffectUnknownInput extends DurableWaitReadInput {
153
190
  readonly reason: string;
191
+ /**
192
+ * Optional for compatibility. When absent, the wait moves to
193
+ * `reconciliation_wait` with the previous (unbound) behavior; such a record
194
+ * is never released by reconcileExternalEffect and needs manual reconciliation.
195
+ */
196
+ readonly external_operation_id?: string;
154
197
  readonly responsible?: DurableWaitResponsible;
155
198
  }
199
+ export interface DurableWaitReconcileExternalEffectInput extends DurableWaitReadInput {
200
+ readonly request_id: string;
201
+ readonly external_operation_id: string;
202
+ readonly evidence_ref: string;
203
+ }
204
+ /** A host-owned verifier must look up authoritative effect evidence, not trust a body verdict. */
205
+ export interface DurableWaitExternalEffectPort {
206
+ verify(input: {
207
+ readonly principal: string;
208
+ readonly wait: DurableWaitRecord;
209
+ readonly claim_id: string;
210
+ readonly external_operation_id: string;
211
+ readonly evidence_ref: string;
212
+ }): DurableWaitExternalEffectVerification | Promise<DurableWaitExternalEffectVerification>;
213
+ }
214
+ export interface DurableWaitExternalEffectVerification {
215
+ readonly wait_id: string;
216
+ readonly claim_id: string;
217
+ readonly external_operation_id: string;
218
+ readonly evidence_ref: string;
219
+ readonly outcome: DurableWaitExternalEffectOutcome;
220
+ }
221
+ /** A host must bind the uncertain operation to its persisted execution intent. */
222
+ export interface DurableWaitUnknownEffectPort {
223
+ verify(input: {
224
+ readonly principal: string;
225
+ readonly wait: DurableWaitRecord;
226
+ readonly claim_id: string;
227
+ readonly external_operation_id: string;
228
+ }): DurableWaitUnknownEffectVerification | Promise<DurableWaitUnknownEffectVerification>;
229
+ }
230
+ export interface DurableWaitUnknownEffectVerification {
231
+ readonly wait_id: string;
232
+ readonly claim_id: string;
233
+ readonly run_id: string;
234
+ readonly external_operation_id: string;
235
+ readonly status: 'unknown';
236
+ }
156
237
  export interface DurableWaitResumeInput extends DurableWaitReadInput {
157
238
  /** Must match the request that won the claim (or the replacement handoff). */
158
239
  readonly request_id: string;
@@ -186,11 +267,13 @@ export interface DurableWaitStoreOptions {
186
267
  readonly dataDir: string;
187
268
  readonly problemSnapshot: DurableWaitProblemSnapshotPort;
188
269
  readonly access?: DurableWaitAccessPort;
270
+ readonly externalEffect?: DurableWaitExternalEffectPort;
271
+ readonly unknownEffect?: DurableWaitUnknownEffectPort;
189
272
  readonly clock?: () => Date;
190
273
  readonly sidecarPath?: string;
191
274
  readonly defaultLeaseMs?: number;
192
275
  }
193
- export type DurableWaitErrorCode = 'invalid_request' | 'not_found' | 'unauthorized' | 'ledger_invalid' | 'problem_snapshot_invalid' | 'condition_unmet' | 'lease_active' | 'lease_expired' | 'state_conflict' | 'reconciliation_required';
276
+ export type DurableWaitErrorCode = 'invalid_request' | 'not_found' | 'unauthorized' | 'authorization_provider_failed' | 'ledger_invalid' | 'problem_snapshot_invalid' | 'condition_unmet' | 'lease_active' | 'lease_expired' | 'state_conflict' | 'reconciliation_required';
194
277
  export declare class DurableWaitError extends Error {
195
278
  readonly code: DurableWaitErrorCode;
196
279
  readonly wait_id?: string;
@@ -201,6 +284,8 @@ export declare class DurableWaitStore {
201
284
  private readonly dataDir;
202
285
  private readonly problemSnapshot;
203
286
  private readonly access;
287
+ private readonly externalEffect?;
288
+ private readonly unknownEffect?;
204
289
  private readonly clock;
205
290
  private readonly sidecarPath;
206
291
  private readonly defaultLeaseMs;
@@ -214,6 +299,8 @@ export declare class DurableWaitStore {
214
299
  readonly principal: string;
215
300
  readonly owner_scope_id?: string;
216
301
  }): Promise<readonly DurableWaitRecord[]>;
302
+ /** Discovery only: claim repeats all live authorization and trigger checks. */
303
+ listDueCandidates(input: DurableWaitDueCandidatesInput): Promise<DurableWaitDueCandidatesPage>;
217
304
  claim(input: DurableWaitClaimInput): Promise<DurableWaitClaimResult>;
218
305
  handoff(input: DurableWaitHandoffInput): Promise<DurableWaitRecord>;
219
306
  /** Explicit name for scheduler adapters that only hand off expired leases. */
@@ -221,6 +308,9 @@ export declare class DurableWaitStore {
221
308
  resume(input: DurableWaitResumeInput): Promise<DurableWaitResumeReceipt>;
222
309
  markPremiseChanged(input: DurableWaitPremiseChangedInput): Promise<DurableWaitRecord>;
223
310
  markEffectUnknown(input: DurableWaitEffectUnknownInput): Promise<DurableWaitRecord>;
311
+ /** Previous behavior, kept for callers that do not send external_operation_id. */
312
+ private markEffectUnknownUnbound;
313
+ reconcileExternalEffect(input: DurableWaitReconcileExternalEffectInput): Promise<DurableWaitRecord>;
224
314
  private captureMutationPreflight;
225
315
  private assertMutationPreflight;
226
316
  private readStored;