@dsh-enhanced/assistant-goals 0.1.30

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 (100) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +274 -0
  3. package/cordis.patch.yml +3 -0
  4. package/lib/budget-store.d.ts +73 -0
  5. package/lib/budget-store.d.ts.map +1 -0
  6. package/lib/budget-store.js +345 -0
  7. package/lib/budget-store.js.map +1 -0
  8. package/lib/budget.d.ts +78 -0
  9. package/lib/budget.d.ts.map +1 -0
  10. package/lib/budget.js +344 -0
  11. package/lib/budget.js.map +1 -0
  12. package/lib/dependency.d.ts +11 -0
  13. package/lib/dependency.d.ts.map +1 -0
  14. package/lib/dependency.js +34 -0
  15. package/lib/dependency.js.map +1 -0
  16. package/lib/event-wait-store.d.ts +56 -0
  17. package/lib/event-wait-store.d.ts.map +1 -0
  18. package/lib/event-wait-store.js +189 -0
  19. package/lib/event-wait-store.js.map +1 -0
  20. package/lib/event-wait.d.ts +47 -0
  21. package/lib/event-wait.d.ts.map +1 -0
  22. package/lib/event-wait.js +372 -0
  23. package/lib/event-wait.js.map +1 -0
  24. package/lib/execution-store.d.ts +23 -0
  25. package/lib/execution-store.d.ts.map +1 -0
  26. package/lib/execution-store.js +207 -0
  27. package/lib/execution-store.js.map +1 -0
  28. package/lib/execution.d.ts +49 -0
  29. package/lib/execution.d.ts.map +1 -0
  30. package/lib/execution.js +438 -0
  31. package/lib/execution.js.map +1 -0
  32. package/lib/feedback.d.ts +63 -0
  33. package/lib/feedback.d.ts.map +1 -0
  34. package/lib/feedback.js +134 -0
  35. package/lib/feedback.js.map +1 -0
  36. package/lib/index.d.ts +27 -0
  37. package/lib/index.d.ts.map +1 -0
  38. package/lib/index.js +9 -0
  39. package/lib/index.js.map +1 -0
  40. package/lib/outcome-store.d.ts +47 -0
  41. package/lib/outcome-store.d.ts.map +1 -0
  42. package/lib/outcome-store.js +271 -0
  43. package/lib/outcome-store.js.map +1 -0
  44. package/lib/outcome.d.ts +77 -0
  45. package/lib/outcome.d.ts.map +1 -0
  46. package/lib/outcome.js +417 -0
  47. package/lib/outcome.js.map +1 -0
  48. package/lib/service.d.ts +363 -0
  49. package/lib/service.d.ts.map +1 -0
  50. package/lib/service.js +1839 -0
  51. package/lib/service.js.map +1 -0
  52. package/lib/store.d.ts +21 -0
  53. package/lib/store.d.ts.map +1 -0
  54. package/lib/store.js +577 -0
  55. package/lib/store.js.map +1 -0
  56. package/lib/strategy-feedback.d.ts +29 -0
  57. package/lib/strategy-feedback.d.ts.map +1 -0
  58. package/lib/strategy-feedback.js +53 -0
  59. package/lib/strategy-feedback.js.map +1 -0
  60. package/lib/strategy-identity.d.ts +11 -0
  61. package/lib/strategy-identity.d.ts.map +1 -0
  62. package/lib/strategy-identity.js +10 -0
  63. package/lib/strategy-identity.js.map +1 -0
  64. package/lib/strategy-store.d.ts +76 -0
  65. package/lib/strategy-store.d.ts.map +1 -0
  66. package/lib/strategy-store.js +277 -0
  67. package/lib/strategy-store.js.map +1 -0
  68. package/lib/strategy.d.ts +56 -0
  69. package/lib/strategy.d.ts.map +1 -0
  70. package/lib/strategy.js +478 -0
  71. package/lib/strategy.js.map +1 -0
  72. package/lib/tools.d.ts +4 -0
  73. package/lib/tools.d.ts.map +1 -0
  74. package/lib/tools.js +130 -0
  75. package/lib/tools.js.map +1 -0
  76. package/lib/types.d.ts +285 -0
  77. package/lib/types.d.ts.map +1 -0
  78. package/lib/types.js +10 -0
  79. package/lib/types.js.map +1 -0
  80. package/lib/verified-artifact.d.ts +72 -0
  81. package/lib/verified-artifact.d.ts.map +1 -0
  82. package/lib/verified-artifact.js +142 -0
  83. package/lib/verified-artifact.js.map +1 -0
  84. package/lib/verified-workflow.d.ts +120 -0
  85. package/lib/verified-workflow.d.ts.map +1 -0
  86. package/lib/verified-workflow.js +253 -0
  87. package/lib/verified-workflow.js.map +1 -0
  88. package/lib/version.d.ts +2 -0
  89. package/lib/version.d.ts.map +1 -0
  90. package/lib/version.js +2 -0
  91. package/lib/version.js.map +1 -0
  92. package/lib/wake-store.d.ts +38 -0
  93. package/lib/wake-store.d.ts.map +1 -0
  94. package/lib/wake-store.js +177 -0
  95. package/lib/wake-store.js.map +1 -0
  96. package/lib/wake.d.ts +45 -0
  97. package/lib/wake.d.ts.map +1 -0
  98. package/lib/wake.js +327 -0
  99. package/lib/wake.js.map +1 -0
  100. package/package.json +143 -0
@@ -0,0 +1,38 @@
1
+ import type { DeliveryPreferencePrincipalAttestation } from '@dsh-enhanced/assistant-delivery';
2
+ import type { GoalDefinition, GoalDependencyBinding, GoalScope, NativeGoalState } from './types.js';
3
+ export interface GoalWakeIntent {
4
+ id: string;
5
+ scope: GoalScope;
6
+ goalId: string;
7
+ definition: GoalDefinition;
8
+ native: NativeGoalState;
9
+ attestation: DeliveryPreferencePrincipalAttestation;
10
+ at: number;
11
+ expiresAt: number;
12
+ ownerRouteId: string;
13
+ budgetId: string;
14
+ /** Optional only for persisted pre-v3 wakes; new intents always bind this list. */
15
+ dependencies?: readonly GoalDependencyBinding[];
16
+ }
17
+ export interface GoalWake {
18
+ intent: GoalWakeIntent;
19
+ state: 'prepared' | 'scheduled' | 'dispatched' | 'succeeded' | 'unknown' | 'denied';
20
+ definitionHash?: string;
21
+ occurrenceId?: string;
22
+ dispatchedAt?: number;
23
+ completedAt?: number;
24
+ }
25
+ export declare function validateGoalWakeIntent(value: GoalWakeIntent): GoalWakeIntent;
26
+ export declare class GoalWakeStore {
27
+ #private;
28
+ constructor(path: string);
29
+ get(id: string): GoalWake | undefined;
30
+ prepare(input: GoalWakeIntent): GoalWake;
31
+ scheduled(id: string, definitionHash: string): GoalWake;
32
+ dispatch(id: string, occurrenceId: string, now: number): GoalWake;
33
+ finish(id: string, outcome: 'succeeded' | 'unknown' | 'denied', now: number): GoalWake;
34
+ listPending(): readonly GoalWake[];
35
+ listForGoal(scope: GoalScope, goalId: string, limit?: number): readonly GoalWake[];
36
+ close(): void;
37
+ }
38
+ //# sourceMappingURL=wake-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wake-store.d.ts","sourceRoot":"","sources":["../src/wake-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sCAAsC,EAAE,MAAM,kCAAkC,CAAA;AAE9F,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAGnG,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,eAAe,CAAA;IACjG,WAAW,EAAE,sCAAsC,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;IAC1H,mFAAmF;IACnF,YAAY,CAAC,EAAE,SAAS,qBAAqB,EAAE,CAAA;CAChD;AACD,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,UAAU,GAAG,WAAW,GAAG,YAAY,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAA;IAC3G,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAC5F;AAaD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,cAAc,GAAG,cAAc,CAe5E;AA4BD,qBAAa,aAAa;;gBAEZ,IAAI,EAAE,MAAM;IAkBxB,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IACrC,OAAO,CAAC,KAAK,EAAE,cAAc,GAAG,QAAQ;IASxC,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,QAAQ;IAUvD,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,QAAQ;IAIjE,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,SAAS,GAAG,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,QAAQ;IAItF,WAAW,IAAI,SAAS,QAAQ,EAAE;IAClC,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,SAAS,QAAQ,EAAE;IAE9E,KAAK,IAAI,IAAI;CACd"}
@@ -0,0 +1,177 @@
1
+ import { DatabaseSync } from 'node:sqlite';
2
+ import { acceptanceCanonicalJson, acceptanceDigest } from '@dsh-enhanced/task-acceptance-contract';
3
+ import { GoalStoreError } from './types.js';
4
+ import { prepareGoalStoreDatabaseFile } from './store.js';
5
+ const idPattern = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,511}$/u;
6
+ const routePattern = /^[A-Za-z0-9][A-Za-z0-9._@/:-]{0,511}$/u;
7
+ function fail(code) { throw new GoalStoreError(code); }
8
+ const same = (a, b) => acceptanceDigest(a) === acceptanceDigest(b);
9
+ const freeze = (value) => { if (value && typeof value === 'object') {
10
+ for (const child of Object.values(value))
11
+ freeze(child);
12
+ Object.freeze(value);
13
+ } ; return value; };
14
+ const integer = (value, min = 0) => Number.isSafeInteger(value) && value >= min;
15
+ const text = (value, max = 512) => typeof value === 'string' && value.length > 0 && value.length <= max && idPattern.test(value);
16
+ const routeText = (value, max = 512) => typeof value === 'string' && value.length > 0 && value.length <= max && routePattern.test(value);
17
+ const plain = (value) => value !== null && typeof value === 'object' && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
18
+ const exact = (value, keys) => plain(value) && Object.keys(value).length === keys.length && keys.every(key => Object.hasOwn(value, key));
19
+ export function validateGoalWakeIntent(value) {
20
+ const keys = ['id', 'scope', 'goalId', 'definition', 'native', 'attestation', 'at', 'expiresAt', 'ownerRouteId', 'budgetId'];
21
+ if (!(exact(value, keys) || exact(value, [...keys, 'dependencies'])) || !text(value.id) || !text(value.goalId) || !routeText(value.ownerRouteId) || !routeText(value.budgetId)
22
+ || !exact(value.scope, ['principalId', 'principalRecordId', 'principalVersion', 'workspace', 'preset']) || !routeText(value.scope.principalId) || !text(value.scope.principalRecordId) || !integer(value.scope.principalVersion, 1) || typeof value.scope.workspace !== 'string' || !value.scope.workspace.startsWith('/') || !text(value.scope.preset)
23
+ || !exact(value.definition, ['version', 'digest', 'objective']) || !integer(value.definition.version, 1) || !/^[a-f0-9]{64}$/u.test(value.definition.digest) || typeof value.definition.objective !== 'string' || value.definition.objective.length < 1 || value.definition.objective.length > 16384 || value.definition.digest !== acceptanceDigest({ objective: value.definition.objective })
24
+ || !exact(value.native, ['sessionId', 'goalId', 'revision', 'objective', 'phase', 'roundsStarted', 'maxGoalRounds', 'updatedAt']) || value.native.phase !== 'paused' || !text(value.native.sessionId) || !text(value.native.goalId) || !integer(value.native.revision, 1) || typeof value.native.objective !== 'string' || value.native.objective.length < 1 || value.native.objective.length > 16384 || !integer(value.native.roundsStarted) || !integer(value.native.maxGoalRounds, 1) || value.native.roundsStarted >= value.native.maxGoalRounds || !integer(value.native.updatedAt)
25
+ || value.native.objective !== value.definition.objective
26
+ || !exact(value.attestation, ['scope', 'principalId', 'principalLineage', 'bindingId', 'bindingVersion', 'bindingGeneration', 'sessionId']) || !exact(value.attestation.scope, ['workspace', 'preset']) || value.attestation.scope.workspace !== value.scope.workspace || value.attestation.scope.preset !== value.scope.preset || value.attestation.principalId !== value.scope.principalId || !exact(value.attestation.principalLineage, ['principalRecordId', 'principalVersion']) || value.attestation.principalLineage.principalRecordId !== value.scope.principalRecordId || value.attestation.principalLineage.principalVersion !== value.scope.principalVersion || value.attestation.sessionId !== value.native.sessionId || !text(value.attestation.bindingId) || !integer(value.attestation.bindingVersion, 1) || !integer(value.attestation.bindingGeneration, 1)
27
+ || !integer(value.at) || !integer(value.expiresAt) || value.expiresAt <= value.at || value.expiresAt - value.at > 300000
28
+ || value.dependencies !== undefined && (!Array.isArray(value.dependencies) || value.dependencies.length > 16
29
+ || new Set(value.dependencies.map(item => item?.goalId)).size !== value.dependencies.length
30
+ || value.dependencies.some(item => !exact(item, ['goalId', 'definitionVersion', 'definitionDigest'])
31
+ || !text(item.goalId) || !integer(item.definitionVersion, 1) || typeof item.definitionDigest !== 'string'
32
+ || !/^[a-f0-9]{64}$/u.test(item.definitionDigest))))
33
+ fail('invalid-input');
34
+ return freeze(JSON.parse(JSON.stringify(value)));
35
+ }
36
+ function parse(value) { try {
37
+ return JSON.parse(value);
38
+ }
39
+ catch {
40
+ return fail('schema');
41
+ } }
42
+ function scopeKey(value) {
43
+ if (!plain(value) || !routeText(value.principalId) || !text(value.principalRecordId) || !integer(value.principalVersion, 1)
44
+ || typeof value.workspace !== 'string' || !value.workspace.startsWith('/') || !text(value.preset))
45
+ fail('invalid-input');
46
+ return acceptanceCanonicalJson({ principalId: value.principalId, principalRecordId: value.principalRecordId, principalVersion: value.principalVersion, workspace: value.workspace, preset: value.preset });
47
+ }
48
+ function wake(row) {
49
+ const intent = validateGoalWakeIntent(parse(row.intent_json));
50
+ if (row.id !== intent.id || row.scope_key !== acceptanceCanonicalJson(intent.scope) || row.goal_id !== intent.goalId)
51
+ fail('schema');
52
+ if (!['prepared', 'scheduled', 'dispatched', 'succeeded', 'unknown', 'denied'].includes(row.state))
53
+ fail('schema');
54
+ const hashValid = /^[a-f0-9]{64}$/u.test(row.definition_hash ?? '');
55
+ if (row.definition_hash !== null && !hashValid)
56
+ fail('schema');
57
+ const dispatched = row.state === 'dispatched' || row.state === 'succeeded' || row.state === 'unknown';
58
+ const terminal = row.state === 'succeeded' || row.state === 'unknown' || row.state === 'denied';
59
+ if (row.state === 'prepared' && row.definition_hash !== null)
60
+ fail('schema');
61
+ if ((row.state === 'scheduled' || dispatched) && !hashValid)
62
+ fail('schema');
63
+ if (dispatched) {
64
+ if (!text(row.occurrence_id) || !integer(row.dispatched_at)
65
+ || row.dispatched_at < intent.at || row.dispatched_at >= intent.expiresAt)
66
+ fail('schema');
67
+ }
68
+ else if (row.occurrence_id !== null || row.dispatched_at !== null)
69
+ fail('schema');
70
+ if (terminal) {
71
+ if (!integer(row.completed_at) || (dispatched && row.completed_at < row.dispatched_at)
72
+ || (row.state === 'succeeded' && row.completed_at >= intent.expiresAt))
73
+ fail('schema');
74
+ }
75
+ else if (row.completed_at !== null)
76
+ fail('schema');
77
+ return freeze({ intent, state: row.state, ...(row.definition_hash === null ? {} : { definitionHash: row.definition_hash }), ...(row.occurrence_id === null ? {} : { occurrenceId: row.occurrence_id }), ...(row.dispatched_at === null ? {} : { dispatchedAt: row.dispatched_at }), ...(row.completed_at === null ? {} : { completedAt: row.completed_at }) });
78
+ }
79
+ export class GoalWakeStore {
80
+ #database;
81
+ constructor(path) {
82
+ if (path !== ':memory:')
83
+ prepareGoalStoreDatabaseFile(path);
84
+ this.#database = new DatabaseSync(path, { enableForeignKeyConstraints: true });
85
+ try {
86
+ this.#database.exec('PRAGMA foreign_keys = ON; PRAGMA busy_timeout = 250; PRAGMA journal_mode = WAL; PRAGMA synchronous = FULL;');
87
+ const version = this.#database.prepare('PRAGMA user_version').get().user_version;
88
+ const tables = this.#database.prepare("SELECT name FROM sqlite_schema WHERE type = 'table' AND name NOT LIKE 'sqlite_%' ORDER BY name").all().map(row => row.name);
89
+ if (version === 0 && tables.length === 0)
90
+ this.#database.exec(`BEGIN IMMEDIATE; CREATE TABLE goal_wakes (id TEXT PRIMARY KEY, intent_json TEXT NOT NULL, state TEXT NOT NULL CHECK(state IN ('prepared','scheduled','dispatched','succeeded','unknown','denied')), definition_hash TEXT, occurrence_id TEXT, dispatched_at INTEGER, completed_at INTEGER, scope_key TEXT NOT NULL, goal_id TEXT NOT NULL) STRICT; CREATE INDEX goal_wakes_scope_goal ON goal_wakes(scope_key, goal_id, id); PRAGMA user_version = 1; COMMIT;`);
91
+ else if (version !== 1 || !same(tables, ['goal_wakes']))
92
+ fail('schema');
93
+ const columns = this.#database.prepare('PRAGMA table_info(goal_wakes)').all().map(row => row.name);
94
+ const sql = this.#database.prepare("SELECT sql FROM sqlite_schema WHERE type = 'table' AND name = 'goal_wakes'").get()?.sql;
95
+ if (!same(columns, ['id', 'intent_json', 'state', 'definition_hash', 'occurrence_id', 'dispatched_at', 'completed_at', 'scope_key', 'goal_id']) || !sql || !/\bSTRICT\b/u.test(sql))
96
+ fail('schema');
97
+ const check = this.#database.prepare('PRAGMA quick_check').get();
98
+ if (check.quick_check !== 'ok')
99
+ fail('schema');
100
+ for (const row of this.#database.prepare('SELECT id, intent_json, state, definition_hash, occurrence_id, dispatched_at, completed_at, scope_key, goal_id FROM goal_wakes').all())
101
+ wake(row);
102
+ if (path !== ':memory:')
103
+ prepareGoalStoreDatabaseFile(path);
104
+ }
105
+ catch (error) {
106
+ this.#database.close();
107
+ throw error;
108
+ }
109
+ }
110
+ #get(id) { const row = this.#database.prepare('SELECT id, intent_json, state, definition_hash, occurrence_id, dispatched_at, completed_at, scope_key, goal_id FROM goal_wakes WHERE id = ?').get(id); return row === undefined ? undefined : wake(row); }
111
+ get(id) { return text(id) ? this.#get(id) : fail('invalid-input'); }
112
+ prepare(input) {
113
+ const intent = validateGoalWakeIntent(input);
114
+ return this.#transaction(() => {
115
+ const current = this.#get(intent.id);
116
+ if (current !== undefined) {
117
+ if (!same(current.intent, intent))
118
+ fail('conflict');
119
+ return current;
120
+ }
121
+ try {
122
+ this.#database.prepare("INSERT INTO goal_wakes(id, intent_json, state, scope_key, goal_id) VALUES (?, ?, 'prepared', ?, ?)").run(intent.id, JSON.stringify(intent), acceptanceCanonicalJson(intent.scope), intent.goalId);
123
+ }
124
+ catch {
125
+ fail('conflict');
126
+ }
127
+ return this.#get(intent.id);
128
+ });
129
+ }
130
+ scheduled(id, definitionHash) {
131
+ if (!text(id) || !/^[a-f0-9]{64}$/u.test(definitionHash))
132
+ fail('invalid-input');
133
+ return this.#transaction(() => {
134
+ const current = this.#get(id);
135
+ if (!current)
136
+ fail('not-found');
137
+ if (current.state === 'scheduled' && current.definitionHash === definitionHash)
138
+ return current;
139
+ if (current.state !== 'prepared')
140
+ fail('conflict');
141
+ if (Number(this.#database.prepare("UPDATE goal_wakes SET state = 'scheduled', definition_hash = ? WHERE id = ? AND state = 'prepared'").run(definitionHash, id).changes) !== 1)
142
+ fail('conflict');
143
+ return this.#get(id);
144
+ });
145
+ }
146
+ dispatch(id, occurrenceId, now) {
147
+ if (!text(id) || !text(occurrenceId) || !integer(now))
148
+ fail('invalid-input');
149
+ return this.#transaction(() => { const current = this.#get(id); if (!current)
150
+ fail('not-found'); if (current.state !== 'scheduled' || now < current.intent.at || now >= current.intent.expiresAt)
151
+ fail('conflict'); if (Number(this.#database.prepare("UPDATE goal_wakes SET state = 'dispatched', occurrence_id = ?, dispatched_at = ? WHERE id = ? AND state = 'scheduled'").run(occurrenceId, now, id).changes) !== 1)
152
+ fail('conflict'); return this.#get(id); });
153
+ }
154
+ finish(id, outcome, now) {
155
+ if (!text(id) || !integer(now) || !['succeeded', 'unknown', 'denied'].includes(outcome))
156
+ fail('invalid-input');
157
+ return this.#transaction(() => { const current = this.#get(id); if (!current)
158
+ fail('not-found'); if (current.state === outcome)
159
+ return current; if ((outcome === 'denied' && (current.state !== 'prepared' && current.state !== 'scheduled')) || (outcome !== 'denied' && (current.state !== 'dispatched' || now < current.dispatchedAt || (outcome === 'succeeded' && now >= current.intent.expiresAt))))
160
+ fail('conflict'); if (Number(this.#database.prepare('UPDATE goal_wakes SET state = ?, completed_at = ? WHERE id = ? AND state = ?').run(outcome, now, id, current.state).changes) !== 1)
161
+ fail('conflict'); return this.#get(id); });
162
+ }
163
+ listPending() { return freeze(this.#database.prepare("SELECT id FROM goal_wakes WHERE state IN ('prepared', 'scheduled') ORDER BY id").all().map(row => this.#get(row.id))); }
164
+ listForGoal(scope, goalId, limit = 20) { if (!text(goalId) || !Number.isSafeInteger(limit) || limit < 1 || limit > 100)
165
+ fail('invalid-input'); return freeze(this.#database.prepare('SELECT id FROM goal_wakes WHERE scope_key = ? AND goal_id = ? ORDER BY id DESC LIMIT ?').all(scopeKey(scope), goalId, limit).map(row => this.#get(row.id))); }
166
+ #transaction(operation) { this.#database.exec('BEGIN IMMEDIATE'); try {
167
+ const result = operation();
168
+ this.#database.exec('COMMIT');
169
+ return result;
170
+ }
171
+ catch (error) {
172
+ this.#database.exec('ROLLBACK');
173
+ throw error;
174
+ } }
175
+ close() { this.#database.close(); }
176
+ }
177
+ //# sourceMappingURL=wake-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wake-store.js","sourceRoot":"","sources":["../src/wake-store.ts"],"names":[],"mappings":"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"}
package/lib/wake.d.ts ADDED
@@ -0,0 +1,45 @@
1
+ import type { Context } from '@deepseek-ai/cordis';
2
+ import type { Agent } from '@deepseek-ai/dsh-agent';
3
+ import type { DeliveryGoalWakeInput, OwnerGoalOutcomeFeedbackTarget } from '@dsh-enhanced/assistant-delivery';
4
+ import type { GoalWake, GoalWakeIntent } from './wake-store.js';
5
+ import type { GoalRecord, GoalScope } from './types.js';
6
+ type VerifiedWakeOutcome = Readonly<{
7
+ assessmentId: string;
8
+ runId: string;
9
+ objectiveStatus: 'achieved' | 'not-achieved';
10
+ }>;
11
+ export interface GoalWakeConfig {
12
+ ownerRouteId: string;
13
+ budgetId: string;
14
+ maxDelayMs?: number;
15
+ runTimeoutMs?: number;
16
+ }
17
+ export declare function validateGoalWakeConfig(value: GoalWakeConfig): Required<GoalWakeConfig>;
18
+ /** One durable at job per owner-authorized intent; Automations owns all scheduling. */
19
+ export declare class GoalWakeRuntime {
20
+ #private;
21
+ private readonly ctx;
22
+ readonly config: Required<GoalWakeConfig>;
23
+ private readonly record;
24
+ private readonly ready;
25
+ private readonly settleExecution;
26
+ private readonly verifiedOutcome;
27
+ private readonly assertEventWait;
28
+ private readonly acceptedEventPause;
29
+ private readonly assertDependencies;
30
+ private readonly dependenciesReady;
31
+ private readonly outcomeFeedbackTarget?;
32
+ constructor(ctx: Context, path: string, config: Required<GoalWakeConfig>, record: (scope: GoalScope, goalId: string, agent?: Agent) => GoalRecord | undefined, ready: () => boolean, settleExecution: (agent: Agent, signal: AbortSignal) => Promise<void>, verifiedOutcome: (record: GoalRecord, wake: GoalWakeIntent['native']) => VerifiedWakeOutcome | undefined, assertEventWait?: (intent: GoalWakeIntent, phase: 'before-resume' | 'running' | 'terminal') => void, acceptedEventPause?: (record: GoalRecord, agent?: Agent) => boolean, assertDependencies?: (record: GoalRecord) => void, dependenciesReady?: () => boolean, outcomeFeedbackTarget?: ((intent: GoalWakeIntent, record: GoalRecord, outcome: VerifiedWakeOutcome) => Readonly<OwnerGoalOutcomeFeedbackTarget>) | undefined);
33
+ owns: (input: DeliveryGoalWakeInput) => boolean;
34
+ health: () => {
35
+ enabled: boolean;
36
+ connected: boolean;
37
+ reconciliationFailures: number;
38
+ };
39
+ reconcile: () => Promise<void>;
40
+ inspect: (scope: GoalScope, goalId: string) => readonly GoalWake[];
41
+ preflight(record: GoalRecord): void;
42
+ materialize(intent: GoalWakeIntent): GoalWake;
43
+ }
44
+ export {};
45
+ //# sourceMappingURL=wake.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wake.d.ts","sourceRoot":"","sources":["../src/wake.ts"],"names":[],"mappings":"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"}
package/lib/wake.js ADDED
@@ -0,0 +1,327 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { acceptanceDigest } from '@dsh-enhanced/task-acceptance-contract';
3
+ import { GoalWakeStore } from './wake-store.js';
4
+ const owner = 'assistant-goals-wake/v1';
5
+ const catalogDigest = acceptanceDigest({ protocol: owner, operation: 'resume-paused-native-goal', version: 1 });
6
+ const hash = (value) => createHash('sha256').update(JSON.stringify(value)).digest('hex');
7
+ const same = (a, b) => acceptanceDigest(a) === acceptanceDigest(b);
8
+ function reject() { throw new Error('assistant-goals: wake authority is unavailable, changed or expired'); }
9
+ export function validateGoalWakeConfig(value) {
10
+ if (!value || typeof value !== 'object' || Array.isArray(value)
11
+ || Object.keys(value).some(key => !['ownerRouteId', 'budgetId', 'maxDelayMs', 'runTimeoutMs'].includes(key))
12
+ || [value.ownerRouteId, value.budgetId].some(item => typeof item !== 'string' || !/^[A-Za-z0-9][A-Za-z0-9._:/-]{0,199}$/u.test(item)))
13
+ reject();
14
+ const config = { ...value, maxDelayMs: value.maxDelayMs ?? 86_400_000, runTimeoutMs: value.runTimeoutMs ?? 60_000 };
15
+ if (!Number.isSafeInteger(config.maxDelayMs) || config.maxDelayMs < 1 || config.maxDelayMs > 31 * 86_400_000
16
+ || !Number.isSafeInteger(config.runTimeoutMs) || config.runTimeoutMs < 1_000 || config.runTimeoutMs > 300_000)
17
+ reject();
18
+ return Object.freeze(config);
19
+ }
20
+ /** One durable at job per owner-authorized intent; Automations owns all scheduling. */
21
+ export class GoalWakeRuntime {
22
+ ctx;
23
+ config;
24
+ record;
25
+ ready;
26
+ settleExecution;
27
+ verifiedOutcome;
28
+ assertEventWait;
29
+ acceptedEventPause;
30
+ assertDependencies;
31
+ dependenciesReady;
32
+ outcomeFeedbackTarget;
33
+ #store;
34
+ #capabilities = new Set();
35
+ #lifecycle = new AbortController();
36
+ #automations;
37
+ #live = true;
38
+ #failures = 0;
39
+ #reconciling = false;
40
+ constructor(ctx, path, config, record, ready, settleExecution, verifiedOutcome, assertEventWait = () => { }, acceptedEventPause = () => false, assertDependencies = () => { }, dependenciesReady = () => true, outcomeFeedbackTarget) {
41
+ this.ctx = ctx;
42
+ this.config = config;
43
+ this.record = record;
44
+ this.ready = ready;
45
+ this.settleExecution = settleExecution;
46
+ this.verifiedOutcome = verifiedOutcome;
47
+ this.assertEventWait = assertEventWait;
48
+ this.acceptedEventPause = acceptedEventPause;
49
+ this.assertDependencies = assertDependencies;
50
+ this.dependenciesReady = dependenciesReady;
51
+ this.outcomeFeedbackTarget = outcomeFeedbackTarget;
52
+ this.#store = new GoalWakeStore(path);
53
+ ctx.inject(['assistantAutomations', 'assistantDelivery', 'assistantPolicy'], runtime => {
54
+ const automations = runtime.assistantAutomations;
55
+ this.#automations = automations;
56
+ const dispose = automations.registerHostExecutor({
57
+ descriptor: { executorId: owner, contractVersion: 1, catalogDigest },
58
+ accepts: spec => spec.executorId === owner && spec.executorContractVersion === 1
59
+ && spec.catalogDigest === catalogDigest && spec.runbookId === 'resume-paused-native-goal'
60
+ && spec.runbookVersion === 1,
61
+ execute: input => this.#execute(input),
62
+ });
63
+ const timer = setInterval(() => { void this.#reconcilePending(); }, 500);
64
+ timer.unref?.();
65
+ void this.#reconcilePending();
66
+ return () => { clearInterval(timer); dispose(); if (this.#automations === automations)
67
+ this.#automations = undefined; };
68
+ });
69
+ ctx.effect(() => () => {
70
+ this.#live = false;
71
+ this.#lifecycle.abort();
72
+ this.#store.close();
73
+ }, 'assistant-goals.wakes');
74
+ }
75
+ owns = (input) => this.#live && this.#automations !== undefined && this.#capabilities.has(input);
76
+ health = () => ({ enabled: true, connected: this.#automations !== undefined, reconciliationFailures: this.#failures });
77
+ reconcile = () => this.#reconcilePending();
78
+ inspect = (scope, goalId) => this.#store.listForGoal(scope, goalId).map(wake => this.#reconcileTerminal(wake));
79
+ async #reconcilePending() {
80
+ if (!this.#live || this.#automations === undefined || !this.ready() || this.#reconciling)
81
+ return;
82
+ this.#reconciling = true;
83
+ try {
84
+ for (const wake of this.#store.listPending()) {
85
+ if ((wake.intent.dependencies?.length ?? 0) > 0 && !this.dependenciesReady())
86
+ continue;
87
+ if (Date.now() < wake.intent.expiresAt) {
88
+ try {
89
+ const record = this.#boundRecord(wake.intent);
90
+ if (!same(record.native, wake.intent.native) || record.native.phase !== 'paused')
91
+ reject();
92
+ }
93
+ catch {
94
+ try {
95
+ this.#store.finish(wake.intent.id, 'denied', Date.now());
96
+ }
97
+ catch {
98
+ this.#failures++;
99
+ }
100
+ continue;
101
+ }
102
+ }
103
+ try {
104
+ this.materialize(wake.intent);
105
+ }
106
+ catch {
107
+ this.#failures++;
108
+ }
109
+ }
110
+ }
111
+ finally {
112
+ this.#reconciling = false;
113
+ }
114
+ }
115
+ #reconcileTerminal(wake) {
116
+ if (wake.state !== 'scheduled' || wake.definitionHash === undefined || this.#automations === undefined)
117
+ return wake;
118
+ const actual = this.#automations.inspectSystemOwned({ owner, automationId: wake.intent.id });
119
+ const terminal = actual.latestTerminalRuns.production;
120
+ if (actual.definitionHash === wake.definitionHash && terminal?.executionMode === 'production'
121
+ && terminal.immutableContext.state === 'verified' && terminal.immutableContext.definitionHash === wake.definitionHash
122
+ && terminal.immutableContext.scope.workspace === wake.intent.scope.workspace
123
+ && terminal.immutableContext.scope.agentPreset === wake.intent.scope.preset) {
124
+ // The scheduler may have stopped after claim but before our CAS. This is
125
+ // proof that no native wake was submitted, not proof its budget was refunded.
126
+ return this.#store.finish(wake.intent.id, 'denied', Date.now());
127
+ }
128
+ return wake;
129
+ }
130
+ preflight(record) {
131
+ if (!this.#live || !this.ready() || this.#automations === undefined)
132
+ reject();
133
+ this.#requireSettlementCapability();
134
+ const policy = this.ctx.get('assistantPolicy');
135
+ if (policy?.getBudgetConfig(this.config.budgetId)?.metric !== 'automation-runs')
136
+ reject();
137
+ this.#route(record.scope, this.config.ownerRouteId);
138
+ this.assertDependencies(record);
139
+ }
140
+ #route(scope, routeId) {
141
+ const receipt = this.ctx.get('assistantDelivery')?.validateOwnerRoute({ authorityId: routeId,
142
+ principalId: scope.principalId, workspace: scope.workspace, agentPreset: scope.preset });
143
+ if (receipt?.principalRecordId !== scope.principalRecordId || receipt.principalVersion !== scope.principalVersion)
144
+ reject();
145
+ }
146
+ #requireSettlementCapability() {
147
+ const delivery = this.ctx.get('assistantDelivery');
148
+ if (delivery?.goalWakeSettlementVersion?.() !== 1)
149
+ reject();
150
+ }
151
+ #boundRecord(intent, agent) {
152
+ const record = this.record(intent.scope, intent.goalId, agent);
153
+ if (record === undefined || !same(record.scope, intent.scope) || !same(record.definition, intent.definition)
154
+ || record.native.sessionId !== intent.native.sessionId || record.native.goalId !== intent.native.goalId
155
+ || record.native.maxGoalRounds !== intent.native.maxGoalRounds)
156
+ reject();
157
+ if (intent.dependencies === undefined
158
+ ? record.checkpoint.dependencies.length > 0
159
+ : !same(record.checkpoint.dependencyBindings ?? [], intent.dependencies))
160
+ reject();
161
+ try {
162
+ this.assertDependencies(record);
163
+ }
164
+ catch {
165
+ reject();
166
+ }
167
+ return record;
168
+ }
169
+ #current(intent, phase, agent) {
170
+ if (!this.#live || !this.ready() || Date.now() >= intent.expiresAt)
171
+ reject();
172
+ this.#requireSettlementCapability();
173
+ if (intent.id.startsWith('goal-event-wake-') && this.ctx.get('assistantDelivery')?.goalWakeResultVersion?.() !== 1)
174
+ reject();
175
+ this.assertEventWait(intent, phase);
176
+ const record = this.#boundRecord(intent, agent);
177
+ const native = record.native;
178
+ const before = native.phase === 'paused' && native.revision === intent.native.revision
179
+ && native.roundsStarted === intent.native.roundsStarted;
180
+ const running = native.phase === 'active' && native.revision === intent.native.revision + 1;
181
+ const terminal = (native.phase === 'complete' || native.phase === 'blocked')
182
+ && native.revision === intent.native.revision + 2;
183
+ const verifiedCompletion = native.phase === 'complete' && native.revision === intent.native.revision + 3
184
+ && this.verifiedOutcome(record, intent.native)?.objectiveStatus === 'achieved';
185
+ const waitingAgain = phase === 'terminal' && native.phase === 'paused' && native.revision === intent.native.revision + 2
186
+ && native.roundsStarted > intent.native.roundsStarted && this.acceptedEventPause(record, agent);
187
+ if (!(phase === 'before-resume' ? before : running || phase === 'terminal' && (terminal || verifiedCompletion || waitingAgain)))
188
+ reject();
189
+ this.#route(intent.scope, intent.ownerRouteId);
190
+ return record;
191
+ }
192
+ materialize(intent) {
193
+ const automations = this.#automations;
194
+ if (automations === undefined || !this.#live)
195
+ reject();
196
+ if (Date.now() >= intent.expiresAt) {
197
+ const expired = this.#store.prepare(intent);
198
+ return expired.state === 'prepared' || expired.state === 'scheduled'
199
+ ? this.#store.finish(intent.id, 'denied', Date.now()) : expired;
200
+ }
201
+ this.#current(intent, 'before-resume');
202
+ const wake = this.#store.prepare(intent);
203
+ if (wake.state !== 'prepared' && wake.state !== 'scheduled')
204
+ return wake;
205
+ const definition = {
206
+ name: 'Scheduled business goal', schedule: { kind: 'at', at: new Date(intent.at).toISOString() },
207
+ workspace: intent.scope.workspace, agentPreset: intent.scope.preset,
208
+ timeoutMs: intent.expiresAt - intent.at, misfire: { kind: 'latest' }, overlap: 'skip',
209
+ retrySafety: 'never', maxRetries: 0, principal: intent.scope.principalId,
210
+ budgetId: intent.budgetId, budgetAmount: 1,
211
+ execution: { kind: 'host', executorId: owner, executorContractVersion: 1,
212
+ runbookId: 'resume-paused-native-goal', runbookVersion: 1, catalogDigest,
213
+ targetScope: { workspace: intent.scope.workspace, preset: intent.scope.preset },
214
+ scopeDigest: '0'.repeat(64), ownerRouteId: intent.ownerRouteId, activationNonce: intent.id },
215
+ };
216
+ // Publish paused first: no coordinator may claim the at occurrence until
217
+ // the exact definition binding is committed in the Goals database.
218
+ const result = automations.reconcileSystem({ owner, automationId: intent.id,
219
+ idempotencyKey: `prepare:${intent.id}`, desiredStatus: 'paused', definition });
220
+ const definitionHash = hash(result.definition);
221
+ this.#store.scheduled(intent.id, definitionHash);
222
+ automations.reconcileSystem({ owner, automationId: intent.id,
223
+ idempotencyKey: `activate:${intent.id}`, desiredStatus: 'active', definition });
224
+ const actual = automations.inspectSystemOwned({ owner, automationId: intent.id });
225
+ if (actual.definitionHash !== definitionHash)
226
+ reject();
227
+ return this.#reconcileTerminal(this.#store.get(intent.id));
228
+ }
229
+ #result(outcome, code, dispatched) {
230
+ return outcome === 'succeeded'
231
+ ? { outcome, failureClass: 'none', failurePhase: 'none', failureCode: 'none', sideEffectState: 'possible', retryability: 'unsafe' }
232
+ : { outcome, failureClass: dispatched ? 'unknown' : 'policy', failurePhase: 'host-execution', failureCode: code,
233
+ sideEffectState: dispatched ? 'unknown' : 'none', retryability: dispatched ? 'unsafe' : 'after-intervention' };
234
+ }
235
+ async #execute(input) {
236
+ const wake = this.#store.get(input.activationNonce);
237
+ if (!this.#live || wake === undefined || input.executionMode !== 'production'
238
+ || wake.intent.id !== input.automationId || wake.definitionHash !== input.definitionHash
239
+ || input.catalogDigest !== catalogDigest || !same(input.targetScope, { workspace: wake.intent.scope.workspace, preset: wake.intent.scope.preset })
240
+ || input.principal !== wake.intent.scope.principalId || input.ownerRouteId !== wake.intent.ownerRouteId) {
241
+ return this.#result('failed', 'goal-wake-identity-denied', false);
242
+ }
243
+ if (wake.state === 'denied')
244
+ return this.#result('failed', 'goal-wake-prior-state', false);
245
+ if (wake.state !== 'scheduled')
246
+ return this.#result('unknown', 'goal-wake-prior-state', true);
247
+ const intent = wake.intent;
248
+ let dispatched = false;
249
+ const signal = AbortSignal.any([input.signal, this.#lifecycle.signal]);
250
+ let terminalSettlement;
251
+ let terminalOutcome;
252
+ let capability;
253
+ capability = Object.freeze({ attestation: intent.attestation,
254
+ native: { goalId: intent.native.goalId, revision: intent.native.revision }, deadlineAt: intent.expiresAt, signal,
255
+ ...(intent.id.startsWith('goal-event-wake-') ? { includeOutput: true } : {}),
256
+ assertCurrent: (agent, phase) => {
257
+ signal.throwIfAborted();
258
+ this.#current(intent, phase, agent);
259
+ const current = this.#store.get(intent.id);
260
+ if (dispatched ? current?.state !== 'dispatched' || current.occurrenceId !== input.occurrenceId
261
+ : current?.state !== 'scheduled')
262
+ reject();
263
+ },
264
+ beforeResume: (agent) => {
265
+ signal.throwIfAborted();
266
+ this.#current(intent, 'before-resume', agent);
267
+ this.#store.dispatch(intent.id, input.occurrenceId, Date.now());
268
+ dispatched = true;
269
+ },
270
+ settle: async (agent, settleSignal) => {
271
+ const combined = AbortSignal.any([signal, settleSignal]);
272
+ combined.throwIfAborted();
273
+ this.#current(intent, 'terminal', agent);
274
+ await this.settleExecution(agent, combined);
275
+ combined.throwIfAborted();
276
+ const settled = this.#current(intent, 'terminal', agent);
277
+ if (settled.native.phase === 'complete' || settled.native.phase === 'blocked') {
278
+ terminalSettlement = settled;
279
+ terminalOutcome = this.verifiedOutcome(settled, intent.native);
280
+ }
281
+ },
282
+ resolveOutcomeFeedbackTarget: () => {
283
+ signal.throwIfAborted();
284
+ if (!this.#capabilities.has(capability) || !dispatched || this.outcomeFeedbackTarget === undefined
285
+ || terminalSettlement === undefined || terminalOutcome === undefined
286
+ || terminalSettlement.native.phase !== 'complete' && terminalSettlement.native.phase !== 'blocked')
287
+ reject();
288
+ const current = this.#current(intent, 'terminal');
289
+ const currentOutcome = this.verifiedOutcome(current, intent.native);
290
+ const wake = this.#store.get(intent.id);
291
+ if (wake?.state !== 'dispatched' || wake.occurrenceId !== input.occurrenceId
292
+ || current.native.phase !== 'complete' && current.native.phase !== 'blocked'
293
+ || !same(current.scope, terminalSettlement.scope) || current.id !== terminalSettlement.id
294
+ || !same(current.definition, terminalSettlement.definition) || !same(current.native, terminalSettlement.native)
295
+ || currentOutcome === undefined || !same(currentOutcome, terminalOutcome))
296
+ reject();
297
+ return this.outcomeFeedbackTarget(intent, current, currentOutcome);
298
+ }, });
299
+ this.#capabilities.add(capability);
300
+ try {
301
+ signal.throwIfAborted();
302
+ this.#current(intent, 'before-resume');
303
+ const delivery = this.ctx.get('assistantDelivery');
304
+ if (delivery === undefined)
305
+ reject();
306
+ const result = await delivery.resumeScheduledGoal(capability);
307
+ if (result.dispatched !== dispatched)
308
+ throw new Error('assistant-goals: wake dispatch disagreement');
309
+ const succeeded = result.outcome === 'succeeded' && result.quiescent && dispatched && !signal.aborted;
310
+ const settled = succeeded ? this.#current(intent, 'terminal') : undefined;
311
+ if (succeeded && settled?.native.phase !== 'paused' && intent.id.startsWith('goal-event-wake-')) {
312
+ delivery.enqueueScheduledGoalResult(capability);
313
+ }
314
+ this.#store.finish(intent.id, succeeded ? 'succeeded' : dispatched ? 'unknown' : 'denied', Date.now());
315
+ return this.#result(succeeded ? 'succeeded' : dispatched ? 'unknown' : 'failed', `goal-wake-${result.outcome}`, dispatched);
316
+ }
317
+ catch {
318
+ if (this.#live)
319
+ this.#store.finish(intent.id, dispatched ? 'unknown' : 'denied', Date.now());
320
+ return this.#result(dispatched ? 'unknown' : 'failed', 'goal-wake-execution-unconfirmed', dispatched);
321
+ }
322
+ finally {
323
+ this.#capabilities.delete(capability);
324
+ }
325
+ }
326
+ }
327
+ //# sourceMappingURL=wake.js.map