@undefineds.co/linx 0.3.5 → 0.3.8

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 (172) hide show
  1. package/README.md +58 -23
  2. package/dist/generated/version.js +1 -1
  3. package/dist/generated/version.js.map +1 -1
  4. package/dist/index.js +336 -162
  5. package/dist/index.js.map +1 -1
  6. package/dist/lib/account-session.js +4 -8
  7. package/dist/lib/account-session.js.map +1 -1
  8. package/dist/lib/ai-command.js +228 -178
  9. package/dist/lib/ai-command.js.map +1 -1
  10. package/dist/lib/auto-mode/archive.js +38 -7
  11. package/dist/lib/auto-mode/archive.js.map +1 -1
  12. package/dist/lib/auto-mode/auth.js.map +1 -1
  13. package/dist/lib/auto-mode/display.js +71 -45
  14. package/dist/lib/auto-mode/display.js.map +1 -1
  15. package/dist/lib/auto-mode/format.js +9 -7
  16. package/dist/lib/auto-mode/format.js.map +1 -1
  17. package/dist/lib/auto-mode/hooks/claude.js +12 -2
  18. package/dist/lib/auto-mode/hooks/claude.js.map +1 -1
  19. package/dist/lib/auto-mode/hooks/codex.js +17 -7
  20. package/dist/lib/auto-mode/hooks/codex.js.map +1 -1
  21. package/dist/lib/auto-mode/hooks/index.js +28 -8
  22. package/dist/lib/auto-mode/hooks/index.js.map +1 -1
  23. package/dist/lib/auto-mode/pod-ai.js +20 -37
  24. package/dist/lib/auto-mode/pod-ai.js.map +1 -1
  25. package/dist/lib/auto-mode/pod-approval.js +124 -195
  26. package/dist/lib/auto-mode/pod-approval.js.map +1 -1
  27. package/dist/lib/auto-mode/pod-persistence.js +169 -90
  28. package/dist/lib/auto-mode/pod-persistence.js.map +1 -1
  29. package/dist/lib/auto-mode/runner.js +683 -81
  30. package/dist/lib/auto-mode/runner.js.map +1 -1
  31. package/dist/lib/auto-mode/secretary.js +186 -41
  32. package/dist/lib/auto-mode/secretary.js.map +1 -1
  33. package/dist/lib/auto-mode-command.js +32 -32
  34. package/dist/lib/auto-mode-command.js.map +1 -1
  35. package/dist/lib/chat-api.js +242 -50
  36. package/dist/lib/chat-api.js.map +1 -1
  37. package/dist/lib/codex-plugin/bridge.js +164 -17
  38. package/dist/lib/codex-plugin/bridge.js.map +1 -1
  39. package/dist/lib/codex-plugin/codex-native-proxy.js +370 -34
  40. package/dist/lib/codex-plugin/codex-native-proxy.js.map +1 -1
  41. package/dist/lib/credentials-store.js +33 -42
  42. package/dist/lib/credentials-store.js.map +1 -1
  43. package/dist/lib/linx-cloud-errors.js +61 -0
  44. package/dist/lib/linx-cloud-errors.js.map +1 -0
  45. package/dist/lib/linx-tui-contract.js +8 -5
  46. package/dist/lib/linx-tui-contract.js.map +1 -1
  47. package/dist/lib/login-command.js +9 -2
  48. package/dist/lib/login-command.js.map +1 -1
  49. package/dist/lib/models.js +3 -20
  50. package/dist/lib/models.js.map +1 -1
  51. package/dist/lib/oidc-auth.js +143 -17
  52. package/dist/lib/oidc-auth.js.map +1 -1
  53. package/dist/lib/oidc-session-storage.js +2 -6
  54. package/dist/lib/oidc-session-storage.js.map +1 -1
  55. package/dist/lib/pi-adapter/auto-input-controller.js +988 -0
  56. package/dist/lib/pi-adapter/auto-input-controller.js.map +1 -0
  57. package/dist/lib/pi-adapter/backend-command.js +2 -0
  58. package/dist/lib/pi-adapter/backend-command.js.map +1 -0
  59. package/dist/lib/pi-adapter/backend-credentials.js +80 -0
  60. package/dist/lib/pi-adapter/backend-credentials.js.map +1 -0
  61. package/dist/lib/pi-adapter/branding.js +246 -108
  62. package/dist/lib/pi-adapter/branding.js.map +1 -1
  63. package/dist/lib/pi-adapter/control-state.js +72 -0
  64. package/dist/lib/pi-adapter/control-state.js.map +1 -0
  65. package/dist/lib/pi-adapter/interactive.js +2634 -30
  66. package/dist/lib/pi-adapter/interactive.js.map +1 -1
  67. package/dist/lib/pi-adapter/pod-approval.js +382 -210
  68. package/dist/lib/pi-adapter/pod-approval.js.map +1 -1
  69. package/dist/lib/pi-adapter/pod-mirror-mapping.js +71 -17
  70. package/dist/lib/pi-adapter/pod-mirror-mapping.js.map +1 -1
  71. package/dist/lib/pi-adapter/pod-mirror.js +531 -64
  72. package/dist/lib/pi-adapter/pod-mirror.js.map +1 -1
  73. package/dist/lib/pi-adapter/pod-native.js +81 -85
  74. package/dist/lib/pi-adapter/pod-native.js.map +1 -1
  75. package/dist/lib/pi-adapter/pod-status-output.js +54 -0
  76. package/dist/lib/pi-adapter/pod-status-output.js.map +1 -0
  77. package/dist/lib/pi-adapter/runtime.js +458 -228
  78. package/dist/lib/pi-adapter/runtime.js.map +1 -1
  79. package/dist/lib/pi-adapter/session-control.js +509 -0
  80. package/dist/lib/pi-adapter/session-control.js.map +1 -0
  81. package/dist/lib/pi-adapter/session.js +35 -22
  82. package/dist/lib/pi-adapter/session.js.map +1 -1
  83. package/dist/lib/pi-adapter/stream.js +89 -32
  84. package/dist/lib/pi-adapter/stream.js.map +1 -1
  85. package/dist/lib/pi-adapter/sync-recovery.js +89 -0
  86. package/dist/lib/pi-adapter/sync-recovery.js.map +1 -0
  87. package/dist/lib/pi-adapter/web-fetch.js +13 -14
  88. package/dist/lib/pi-adapter/web-fetch.js.map +1 -1
  89. package/dist/lib/pod-chat-store.js +254 -78
  90. package/dist/lib/pod-chat-store.js.map +1 -1
  91. package/dist/lib/pod-data-session.js +156 -35
  92. package/dist/lib/pod-data-session.js.map +1 -1
  93. package/dist/lib/solid-auth-store.js +27 -0
  94. package/dist/lib/solid-auth-store.js.map +1 -0
  95. package/dist/lib/solid-auth.js +2 -4
  96. package/dist/lib/solid-auth.js.map +1 -1
  97. package/dist/lib/solid-client-credentials-login.js +100 -0
  98. package/dist/lib/solid-client-credentials-login.js.map +1 -0
  99. package/dist/lib/solid-local-store.js +31 -0
  100. package/dist/lib/solid-local-store.js.map +1 -0
  101. package/dist/lib/symphony/archive.js +328 -18
  102. package/dist/lib/symphony/archive.js.map +1 -1
  103. package/dist/lib/symphony/pod-projection.js +2222 -0
  104. package/dist/lib/symphony/pod-projection.js.map +1 -0
  105. package/dist/lib/symphony-command.js +602 -178
  106. package/dist/lib/symphony-command.js.map +1 -1
  107. package/dist/lib/sync-checkpoint-store.js +74 -0
  108. package/dist/lib/sync-checkpoint-store.js.map +1 -0
  109. package/dist/skills/symphony/SKILL.md +665 -0
  110. package/package.json +15 -9
  111. package/vendor/agent-runtime/dist/agent-runtime.d.ts +137 -0
  112. package/vendor/agent-runtime/dist/agent-runtime.js +211 -0
  113. package/vendor/agent-runtime/dist/auto-mode.d.ts +78 -13
  114. package/vendor/agent-runtime/dist/auto-mode.js +288 -31
  115. package/vendor/agent-runtime/dist/control-plane.d.ts +28 -0
  116. package/vendor/agent-runtime/dist/control-plane.js +79 -0
  117. package/vendor/agent-runtime/dist/file-sync.d.ts +157 -0
  118. package/vendor/agent-runtime/dist/file-sync.js +314 -0
  119. package/vendor/agent-runtime/dist/index.d.ts +7 -0
  120. package/vendor/agent-runtime/dist/index.js +7 -0
  121. package/vendor/agent-runtime/dist/reconciler.d.ts +117 -0
  122. package/vendor/agent-runtime/dist/reconciler.js +361 -0
  123. package/vendor/agent-runtime/dist/symphony.d.ts +128 -8
  124. package/vendor/agent-runtime/dist/symphony.js +362 -57
  125. package/vendor/agent-runtime/dist/sync.d.ts +271 -0
  126. package/vendor/agent-runtime/dist/sync.js +550 -0
  127. package/vendor/agent-runtime/dist/thread-reconciler-controller.d.ts +58 -0
  128. package/vendor/agent-runtime/dist/thread-reconciler-controller.js +137 -0
  129. package/vendor/agent-runtime/dist/turn-controller.js +2 -2
  130. package/vendor/agent-runtime/dist/wake-scheduler.d.ts +67 -0
  131. package/vendor/agent-runtime/dist/wake-scheduler.js +194 -0
  132. package/vendor/agent-runtime/package.json +8 -1
  133. package/vendor/pi-web-access/CHANGELOG.md +387 -0
  134. package/vendor/pi-web-access/LICENSE +21 -0
  135. package/vendor/pi-web-access/README.md +352 -0
  136. package/vendor/pi-web-access/activity.ts +101 -0
  137. package/vendor/pi-web-access/banner.png +0 -0
  138. package/vendor/pi-web-access/chrome-cookies.ts +322 -0
  139. package/vendor/pi-web-access/code-search.ts +107 -0
  140. package/vendor/pi-web-access/curator-page.ts +3359 -0
  141. package/vendor/pi-web-access/curator-server.ts +605 -0
  142. package/vendor/pi-web-access/exa.ts +520 -0
  143. package/vendor/pi-web-access/extract.ts +641 -0
  144. package/vendor/pi-web-access/gemini-api.ts +112 -0
  145. package/vendor/pi-web-access/gemini-search.ts +361 -0
  146. package/vendor/pi-web-access/gemini-url-context.ts +126 -0
  147. package/vendor/pi-web-access/gemini-web-config.ts +52 -0
  148. package/vendor/pi-web-access/gemini-web.ts +396 -0
  149. package/vendor/pi-web-access/github-api.ts +196 -0
  150. package/vendor/pi-web-access/github-extract.ts +634 -0
  151. package/vendor/pi-web-access/index.ts +2346 -0
  152. package/vendor/pi-web-access/package.json +45 -0
  153. package/vendor/pi-web-access/pdf-extract.ts +192 -0
  154. package/vendor/pi-web-access/perplexity.ts +195 -0
  155. package/vendor/pi-web-access/pi-web-fetch-demo.mp4 +0 -0
  156. package/vendor/pi-web-access/rsc-extract.ts +338 -0
  157. package/vendor/pi-web-access/skills/librarian/SKILL.md +195 -0
  158. package/vendor/pi-web-access/storage.ts +72 -0
  159. package/vendor/pi-web-access/summary-review.ts +276 -0
  160. package/vendor/pi-web-access/test/gemini-web-cookie-opt-in.test.mjs +41 -0
  161. package/vendor/pi-web-access/test/pdf-extract.test.mjs +95 -0
  162. package/vendor/pi-web-access/utils.ts +44 -0
  163. package/vendor/pi-web-access/video-extract.ts +378 -0
  164. package/vendor/pi-web-access/youtube-extract.ts +310 -0
  165. package/dist/lib/pi-adapter/auth.js +0 -68
  166. package/dist/lib/pi-adapter/auth.js.map +0 -1
  167. package/dist/lib/pi-adapter/pod-tools.js +0 -140
  168. package/dist/lib/pi-adapter/pod-tools.js.map +0 -1
  169. package/dist/skills/drizzle-solid/SKILL.md +0 -340
  170. package/dist/skills/pod-storage/SKILL.md +0 -100
  171. package/dist/skills/solid-modeling/SKILL.md +0 -274
  172. package/dist/skills/xpod-componentsjs/SKILL.md +0 -284
@@ -0,0 +1,361 @@
1
+ const DEFAULT_SECRETARY_AGENT = '__secretary__';
2
+ const DEFAULT_ASSISTANT_AGENT = 'primary-agent';
3
+ const DEFAULT_REVIEWER_AGENT = 'ai-reviewer';
4
+ export function createThreadReconciler(policy) {
5
+ const normalized = normalizeThreadPolicy(policy);
6
+ return {
7
+ policy: normalized,
8
+ reconcile(event, options = {}) {
9
+ return reconcileThreadEvent({
10
+ ...options,
11
+ policy: normalized,
12
+ event,
13
+ });
14
+ },
15
+ };
16
+ }
17
+ export function reconcileThreadEvent(input) {
18
+ const policy = normalizeThreadPolicy(input.policy);
19
+ const createdAt = (input.now ?? new Date()).toISOString();
20
+ const event = normalizeThreadEvent(input.event, input, createdAt);
21
+ const placement = resolveThreadPlacement({
22
+ event,
23
+ chat: input.chat,
24
+ thread: input.thread,
25
+ randomId: input.randomId,
26
+ });
27
+ const jobs = selectWakeJobs(policy, event, placement, createdAt, input.randomId);
28
+ const skippedReason = jobs.length === 0 ? skipReasonFor(policy, event) : undefined;
29
+ return {
30
+ id: createReconcilerId('decision', input.randomId),
31
+ policyKind: policy.kind,
32
+ event,
33
+ placement,
34
+ wakeJobs: jobs,
35
+ ...(skippedReason ? { skippedReason } : {}),
36
+ createdAt,
37
+ };
38
+ }
39
+ export function summarizeReconcileDecision(decision) {
40
+ return {
41
+ id: decision.id,
42
+ policyKind: decision.policyKind,
43
+ eventType: decision.event.type,
44
+ thread: decision.placement.thread,
45
+ ...(decision.placement.chat ? { chat: decision.placement.chat } : {}),
46
+ ...(decision.skippedReason ? { skippedReason: decision.skippedReason } : {}),
47
+ wakeJobs: decision.wakeJobs.map((job) => ({
48
+ id: job.id,
49
+ thread: job.thread,
50
+ ...(job.chat ? { chat: job.chat } : {}),
51
+ targetAgent: job.targetAgent,
52
+ targetRole: job.targetRole,
53
+ trigger: job.trigger,
54
+ priority: job.priority,
55
+ status: job.status,
56
+ reason: job.reason,
57
+ ...(job.sourceEventId ? { sourceEventId: job.sourceEventId } : {}),
58
+ sourceEventType: job.sourceEventType,
59
+ ...(decision.event.resource ? { sourceResource: decision.event.resource } : {}),
60
+ ...(resolveControlGate(decision.event) ? { controlGate: resolveControlGate(decision.event) } : {}),
61
+ })),
62
+ createdAt: decision.createdAt,
63
+ };
64
+ }
65
+ export function resolveThreadPlacement(input) {
66
+ const chat = normalizeText(input.event.chat) ?? normalizeText(input.chat);
67
+ const explicitThread = normalizeText(input.event.thread) ?? normalizeText(input.thread);
68
+ if (input.event.type === 'schedule.tick') {
69
+ const scheduleId = normalizeText(input.event.resource)
70
+ ?? normalizeText(input.event.data?.schedule)
71
+ ?? normalizeText(input.event.data?.scheduleId)
72
+ ?? normalizeText(input.event.id)
73
+ ?? normalizeText(input.randomId)
74
+ ?? 'default';
75
+ const scheduleThread = explicitThread ?? createSyntheticThreadUri('schedule', scheduleId);
76
+ const shouldSplit = input.event.data?.splitThread === true
77
+ || input.event.data?.longRunning === true
78
+ || input.event.data?.noisy === true
79
+ || input.event.data?.needsReview === true
80
+ || input.event.data?.workerOwned === true;
81
+ if (shouldSplit) {
82
+ return {
83
+ ...(chat ? { chat } : {}),
84
+ thread: createSyntheticThreadUri('schedule-run', `${scheduleId}-${input.randomId ?? input.event.id ?? 'tick'}`),
85
+ kind: 'schedule_run',
86
+ parentThread: scheduleThread,
87
+ rootThread: scheduleThread,
88
+ splitFrom: scheduleThread,
89
+ splitReason: normalizeText(input.event.data?.splitReason) ?? 'schedule tick needs an execution thread',
90
+ };
91
+ }
92
+ return {
93
+ ...(chat ? { chat } : {}),
94
+ thread: scheduleThread,
95
+ kind: 'schedule',
96
+ };
97
+ }
98
+ if (explicitThread) {
99
+ return {
100
+ ...(chat ? { chat } : {}),
101
+ thread: explicitThread,
102
+ kind: threadKindFromEvent(input.event),
103
+ };
104
+ }
105
+ if (chat) {
106
+ return {
107
+ chat,
108
+ thread: createSyntheticThreadUri('control', chat),
109
+ kind: 'control',
110
+ };
111
+ }
112
+ return {
113
+ thread: 'urn:undefineds:linx:thread:system-control',
114
+ kind: 'control',
115
+ };
116
+ }
117
+ function selectWakeJobs(policy, event, placement, createdAt, randomId) {
118
+ if (policy.kind === 'direct') {
119
+ return isUserMessage(event)
120
+ ? [createWakeJob(policy, event, placement, {
121
+ targetAgent: policy.defaultAssistantAgent ?? DEFAULT_ASSISTANT_AGENT,
122
+ targetRole: 'primary-agent',
123
+ priority: 'normal',
124
+ reason: 'Direct thread routes user messages to the default assistant.',
125
+ createdAt,
126
+ randomId,
127
+ })]
128
+ : [];
129
+ }
130
+ if (policy.kind === 'auto') {
131
+ if (isInputApprovalOrBlocker(event)) {
132
+ return [createSecretaryWakeJob(policy, event, placement, 'Auto mode routes input, approval, and blocker events to the same-Thread Secretary.', 'high', createdAt, randomId)];
133
+ }
134
+ if (isUserMessage(event)) {
135
+ return [createSecretaryWakeJob(policy, event, placement, 'Auto mode routes user messages and steering input to the same-Thread Secretary before runtime projection.', 'normal', createdAt, randomId)];
136
+ }
137
+ if (isPrimaryAgentMessage(event)) {
138
+ return [createSecretaryWakeJob(policy, event, placement, 'Auto mode treats the latest backend message as a candidate next user-input slot.', 'normal', createdAt, randomId)];
139
+ }
140
+ return [];
141
+ }
142
+ if (policy.kind === 'symphony') {
143
+ if (isInputApprovalOrBlocker(event) || event.type === 'change.requested') {
144
+ return [createSecretaryWakeJob(policy, event, placement, 'Symphony routes blocker, input, approval, and change requests to Secretary for semantic judgment.', 'high', createdAt, randomId)];
145
+ }
146
+ if (event.type === 'delivery.submitted') {
147
+ if (isTaskDispatchDelivery(event) && policy.assignedWorkerAgent) {
148
+ return [createWakeJob(policy, event, placement, {
149
+ targetAgent: policy.assignedWorkerAgent,
150
+ targetRole: 'worker',
151
+ priority: 'normal',
152
+ reason: 'Symphony task-dispatch Delivery wakes the assigned worker through the scheduler.',
153
+ createdAt,
154
+ randomId,
155
+ })];
156
+ }
157
+ return [createSecretaryWakeJob(policy, event, placement, 'Symphony Delivery submissions wake Secretary for review or routing.', 'normal', createdAt, randomId)];
158
+ }
159
+ if (event.type === 'delivery.completed') {
160
+ return [createSecretaryWakeJob(policy, event, placement, 'Symphony completion Delivery wakes Secretary for quality and acceptance reconciliation.', 'high', createdAt, randomId)];
161
+ }
162
+ if (event.type === 'delivery.failed') {
163
+ return [createSecretaryWakeJob(policy, event, placement, 'Symphony failed Delivery wakes Secretary for feasibility, retry, or scope change reconciliation.', 'high', createdAt, randomId)];
164
+ }
165
+ if (event.type === 'issue.updated' || event.type === 'task.updated' || event.type === 'run.updated') {
166
+ return [createSecretaryWakeJob(policy, event, placement, 'Symphony state changes wake Secretary to reconcile system state.', 'normal', createdAt, randomId)];
167
+ }
168
+ if (event.type === 'schedule.tick') {
169
+ return [createSecretaryWakeJob(policy, event, placement, 'Schedule ticks are Thread events; Symphony wakes Secretary to decide whether to keep, split, or dispatch work.', 'normal', createdAt, randomId)];
170
+ }
171
+ return [];
172
+ }
173
+ if (policy.kind === 'open_group') {
174
+ const targets = resolveOpenGroupTargets(policy, event);
175
+ return targets.map((agent, index) => createWakeJob(policy, event, placement, {
176
+ targetAgent: agent.id,
177
+ targetRole: agent.role ?? 'primary-agent',
178
+ priority: 'normal',
179
+ reason: agent.subscribed ? 'Open group policy wakes a subscribed agent.' : 'Open group policy wakes a mentioned agent.',
180
+ createdAt,
181
+ randomId: `${randomId ?? event.id ?? 'event'}-${index + 1}`,
182
+ }));
183
+ }
184
+ if (policy.kind === 'review') {
185
+ if (event.type === 'delivery.submitted' || event.type === 'delivery.completed' || event.type === 'delivery.failed') {
186
+ const reviewer = policy.reviewerAgent ?? policy.secretaryAgent ?? DEFAULT_REVIEWER_AGENT;
187
+ return [createWakeJob(policy, event, placement, {
188
+ targetAgent: reviewer,
189
+ targetRole: policy.reviewerAgent ? 'reviewer' : 'secretary',
190
+ priority: event.type === 'delivery.failed' ? 'high' : 'normal',
191
+ reason: 'Review policy routes Delivery boundaries to reviewer or Secretary.',
192
+ createdAt,
193
+ randomId,
194
+ })];
195
+ }
196
+ return [];
197
+ }
198
+ return [];
199
+ }
200
+ function createSecretaryWakeJob(policy, event, placement, reason, priority, createdAt, randomId) {
201
+ return createWakeJob(policy, event, placement, {
202
+ targetAgent: policy.secretaryAgent ?? DEFAULT_SECRETARY_AGENT,
203
+ targetRole: 'secretary',
204
+ priority,
205
+ reason,
206
+ createdAt,
207
+ randomId,
208
+ });
209
+ }
210
+ function createWakeJob(_policy, event, placement, input) {
211
+ return {
212
+ id: createReconcilerId('wake', input.randomId ?? event.id),
213
+ thread: placement.thread,
214
+ ...(placement.chat ? { chat: placement.chat } : {}),
215
+ targetAgent: input.targetAgent,
216
+ targetRole: input.targetRole,
217
+ trigger: event.type,
218
+ priority: input.priority,
219
+ status: 'queued',
220
+ reason: input.reason,
221
+ ...(event.id ? { sourceEventId: event.id } : {}),
222
+ sourceEventType: event.type,
223
+ createdAt: input.createdAt,
224
+ };
225
+ }
226
+ function normalizeThreadPolicy(policy) {
227
+ return typeof policy === 'string' ? { kind: policy } : policy;
228
+ }
229
+ function normalizeThreadEvent(event, input, createdAt) {
230
+ return {
231
+ ...event,
232
+ ...(event.chat ?? input.chat ? { chat: event.chat ?? input.chat } : {}),
233
+ ...(event.thread ?? input.thread ? { thread: event.thread ?? input.thread } : {}),
234
+ id: event.id ?? createReconcilerId('event', input.randomId),
235
+ createdAt: event.createdAt ?? createdAt,
236
+ };
237
+ }
238
+ function threadKindFromEvent(event) {
239
+ if (event.type === 'delivery.submitted' || event.type === 'delivery.completed' || event.type === 'delivery.failed') {
240
+ return 'worker';
241
+ }
242
+ if (event.type === 'schedule.tick') {
243
+ return 'schedule';
244
+ }
245
+ if (event.type === 'issue.updated' || event.type === 'task.updated' || event.type === 'run.updated') {
246
+ return 'control';
247
+ }
248
+ return 'main';
249
+ }
250
+ function isInputApprovalOrBlocker(event) {
251
+ return event.type === 'input.required' || event.type === 'approval.required' || event.type === 'worker.blocked';
252
+ }
253
+ function resolveControlGate(event) {
254
+ if (event.type === 'input.required' || event.type === 'approval.required') {
255
+ return 'authority';
256
+ }
257
+ if (event.type === 'worker.blocked') {
258
+ return 'feasibility';
259
+ }
260
+ if (event.type === 'change.requested') {
261
+ return 'change';
262
+ }
263
+ if (event.type === 'delivery.completed') {
264
+ return 'quality';
265
+ }
266
+ if (event.type === 'delivery.failed') {
267
+ return 'feasibility';
268
+ }
269
+ if (event.type === 'issue.updated' || event.type === 'task.updated' || event.type === 'run.updated') {
270
+ return 'binding';
271
+ }
272
+ if (event.type === 'schedule.tick') {
273
+ return 'binding';
274
+ }
275
+ return undefined;
276
+ }
277
+ function isUserMessage(event) {
278
+ return event.type === 'message.appended'
279
+ && (event.actor?.role === 'user' || event.data?.role === 'user');
280
+ }
281
+ function isPrimaryAgentMessage(event) {
282
+ if (event.actor?.role === 'secretary') {
283
+ return false;
284
+ }
285
+ return event.type === 'message.appended'
286
+ && (event.actor?.role === 'primary-agent'
287
+ || event.actor?.role === 'assistant'
288
+ || event.actor?.role === 'worker'
289
+ || event.actor?.role === 'runtime'
290
+ || event.data?.role === 'assistant'
291
+ || event.data?.source === 'primary-agent');
292
+ }
293
+ function isTaskDispatchDelivery(event) {
294
+ return event.data?.deliveryType === 'task_dispatch'
295
+ || event.data?.type === 'task_dispatch'
296
+ || event.data?.dispatch === true;
297
+ }
298
+ function resolveOpenGroupTargets(policy, event) {
299
+ const agents = policy.agents ?? [];
300
+ const explicit = normalizeStringArray(event.data?.mentions);
301
+ const mentioned = explicit.length > 0
302
+ ? agents.filter((agent) => {
303
+ const aliases = [agent.id, ...(agent.aliases ?? [])].map((item) => item.toLowerCase());
304
+ return explicit.some((mention) => aliases.includes(mention.toLowerCase()));
305
+ })
306
+ : agents.filter((agent) => isMentioned(event.content, agent));
307
+ const subscribed = agents.filter((agent) => {
308
+ if (!agent.subscribed) {
309
+ return false;
310
+ }
311
+ return !mentioned.some((item) => item.id === agent.id);
312
+ });
313
+ const subscribedIds = new Set(policy.subscribedAgents ?? []);
314
+ const policySubscribed = agents.filter((agent) => {
315
+ if (!subscribedIds.has(agent.id)) {
316
+ return false;
317
+ }
318
+ return !mentioned.some((item) => item.id === agent.id) && !subscribed.some((item) => item.id === agent.id);
319
+ });
320
+ return [...mentioned, ...subscribed, ...policySubscribed];
321
+ }
322
+ function isMentioned(content, agent) {
323
+ if (!content) {
324
+ return false;
325
+ }
326
+ const normalized = content.toLowerCase();
327
+ return [agent.id, ...(agent.aliases ?? [])]
328
+ .filter(Boolean)
329
+ .some((name) => normalized.includes(`@${name.toLowerCase()}`));
330
+ }
331
+ function skipReasonFor(policy, event) {
332
+ if (policy.kind === 'open_group') {
333
+ return 'No mentioned or subscribed agents matched the event.';
334
+ }
335
+ return `Policy ${policy.kind} does not wake an agent for ${event.type}.`;
336
+ }
337
+ function createSyntheticThreadUri(kind, value) {
338
+ return `urn:undefineds:linx:thread:${kind}:${safeUriSegment(value)}`;
339
+ }
340
+ function createReconcilerId(prefix, randomId) {
341
+ const suffix = normalizeText(randomId)
342
+ ?? globalThis.crypto?.randomUUID?.()
343
+ ?? Math.random().toString(36).slice(2, 10).padEnd(8, '0');
344
+ return `${prefix}_${safeUriSegment(suffix)}`;
345
+ }
346
+ function normalizeText(value) {
347
+ return typeof value === 'string' && value.trim() ? value.trim() : undefined;
348
+ }
349
+ function normalizeStringArray(value) {
350
+ return Array.isArray(value)
351
+ ? value.map((item) => normalizeText(item)).filter((item) => Boolean(item))
352
+ : [];
353
+ }
354
+ function safeUriSegment(value) {
355
+ const normalized = value
356
+ .replace(/[^a-zA-Z0-9._:-]/gu, '-')
357
+ .replace(/-+/gu, '-')
358
+ .replace(/^-|-$/gu, '')
359
+ .slice(0, 160);
360
+ return normalized || 'unknown';
361
+ }
@@ -1,29 +1,84 @@
1
- import type { AutoModeBackend, AutoModeMode } from './auto-mode.js';
1
+ import type { AutoModeMode, AutoModeWorkerBackend } from './auto-mode.js';
2
+ import { type ReconcileDecision, type ReconcileDecisionSummary } from './reconciler.js';
2
3
  export declare const SYMPHONY_HOME_DIRNAME = "symphony";
4
+ export declare const SYMPHONY_IDEAS_DIRNAME = "ideas";
3
5
  export declare const SYMPHONY_ISSUES_DIRNAME = "issues";
6
+ export declare const SYMPHONY_TASKS_DIRNAME = "tasks";
4
7
  export declare const SYMPHONY_DELIVERIES_DIRNAME = "deliveries";
5
8
  export declare const SYMPHONY_SESSIONS_DIRNAME = "sessions";
9
+ export declare const SYMPHONY_IDEA_FILE_NAME = "idea.json";
6
10
  export declare const SYMPHONY_ISSUE_FILE_NAME = "issue.json";
11
+ export declare const SYMPHONY_TASK_FILE_NAME = "task.json";
7
12
  export declare const SYMPHONY_DELIVERY_FILE_NAME = "delivery.json";
8
13
  export declare const SYMPHONY_SESSION_FILE_NAME = "session.json";
9
14
  export type SymphonyWorkspaceKind = 'git' | 'folder';
15
+ export type SymphonyIdeaStatus = 'captured' | 'exploring' | 'candidate' | 'promoted' | 'deferred' | 'rejected' | 'superseded';
16
+ export type SymphonyIdeaCommitment = 'thought' | 'direction' | 'tentative_decision' | 'committed';
10
17
  export type SymphonyIssueStatus = 'open' | 'triaging' | 'in_progress' | 'blocked' | 'resolved' | 'closed';
18
+ export type SymphonyTaskStatus = 'pending' | 'running' | 'completed' | 'failed';
11
19
  export type SymphonyDeliveryStatus = 'pending' | 'dispatched' | 'completed' | 'failed';
12
20
  export type SymphonySessionStatus = 'planned' | 'running' | 'completed' | 'failed';
13
21
  export type SymphonyProjectionRole = 'user' | 'system' | 'tool';
14
- export type SymphonyResourceKind = 'issue' | 'task' | 'delivery' | 'session';
22
+ export type SymphonyResourceKind = 'idea' | 'issue' | 'task' | 'delivery' | 'session';
23
+ export interface SymphonyReconcilerState {
24
+ decisions: ReconcileDecisionSummary[];
25
+ }
15
26
  export interface SymphonyWorkspaceRef {
16
27
  path: string;
17
28
  kind: SymphonyWorkspaceKind;
18
29
  repository?: string;
19
30
  branch?: string;
20
31
  worktree?: string;
32
+ workspaceUri?: string;
33
+ baseRevision?: string;
34
+ environment?: SymphonyWorkerEnvironmentRef;
35
+ }
36
+ export interface SymphonyWorkerEnvironmentRef {
37
+ kind: 'local-shell' | 'remote-container' | 'cloud-runner' | 'backend-runtime' | 'unknown';
38
+ id?: string;
39
+ label?: string;
40
+ runtime?: AutoModeWorkerBackend | string;
41
+ }
42
+ export interface SymphonySupervisorPolicy {
43
+ strategy: 'interval';
44
+ intervalMs: number;
45
+ immediateWakeKinds: string[];
46
+ }
47
+ export interface SymphonyIssuerRef extends SymphonyChatThreadRef {
48
+ source: 'user' | 'secretary' | 'system';
49
+ webId?: string;
50
+ agent?: string;
51
+ label?: string;
21
52
  }
22
53
  export interface SymphonyChatThreadRef {
23
54
  chat?: string;
24
55
  thread?: string;
25
56
  messages?: string[];
26
57
  }
58
+ export type SymphonyDelegationTargetSource = 'active-session' | 'group-chat' | 'ai-contact' | 'explicit-backend' | 'default';
59
+ export interface SymphonyDelegationTarget extends SymphonyChatThreadRef {
60
+ source: SymphonyDelegationTargetSource;
61
+ backend: AutoModeWorkerBackend;
62
+ agent?: string;
63
+ label?: string;
64
+ }
65
+ export interface SymphonyIdeaRecord extends SymphonyChatThreadRef {
66
+ uri: string;
67
+ summary: string;
68
+ input?: string;
69
+ status: SymphonyIdeaStatus;
70
+ commitment: SymphonyIdeaCommitment;
71
+ source: 'cli';
72
+ affectedArea?: string;
73
+ currentUnderstanding?: string;
74
+ openQuestions: string[];
75
+ relatedRecords: string[];
76
+ conflicts: string[];
77
+ nextStep?: string;
78
+ promotedTo?: string;
79
+ createdAt: string;
80
+ updatedAt: string;
81
+ }
27
82
  export interface SymphonyIssueRecord extends SymphonyChatThreadRef {
28
83
  uri: string;
29
84
  title: string;
@@ -31,27 +86,50 @@ export interface SymphonyIssueRecord extends SymphonyChatThreadRef {
31
86
  status: SymphonyIssueStatus;
32
87
  priority: 'low' | 'medium' | 'high' | 'urgent';
33
88
  source: 'cli';
89
+ issuer: SymphonyIssuerRef;
34
90
  tasks: string[];
91
+ deliveries: string[];
92
+ sessions: string[];
35
93
  createdAt: string;
36
94
  updatedAt: string;
37
95
  closedAt?: string;
38
96
  error?: string;
39
97
  }
98
+ export interface SymphonyTaskRecord extends SymphonyChatThreadRef {
99
+ uri: string;
100
+ issue: string;
101
+ title: string;
102
+ objective: string;
103
+ acceptanceCriteria: string[];
104
+ status: SymphonyTaskStatus;
105
+ target: SymphonyDelegationTarget;
106
+ backend: AutoModeWorkerBackend;
107
+ agent?: string;
108
+ delivery: string;
109
+ session: string;
110
+ reconciler?: SymphonyReconcilerState;
111
+ createdAt: string;
112
+ updatedAt: string;
113
+ completedAt?: string;
114
+ error?: string;
115
+ }
40
116
  export interface SymphonyDeliveryRecord extends SymphonyChatThreadRef {
41
117
  uri: string;
42
118
  issue: string;
43
119
  task: string;
44
120
  type: 'task_dispatch';
45
121
  status: SymphonyDeliveryStatus;
46
- sourceAgent: 'ai-secretary';
47
- targetBackend: AutoModeBackend;
122
+ sourceAgent: '__secretary__';
123
+ targetBackend: AutoModeWorkerBackend;
48
124
  targetAgent: string;
125
+ target: SymphonyDelegationTarget;
49
126
  projection: {
50
127
  runtimeRole: SymphonyProjectionRole;
51
128
  prompt: string;
52
129
  };
53
130
  session?: string;
54
131
  autoModeSessionId?: string;
132
+ reconciler?: SymphonyReconcilerState;
55
133
  createdAt: string;
56
134
  updatedAt: string;
57
135
  completedAt?: string;
@@ -62,14 +140,19 @@ export interface SymphonySessionRecord extends SymphonyChatThreadRef {
62
140
  issue: string;
63
141
  task: string;
64
142
  delivery: string;
65
- backend: AutoModeBackend;
143
+ backend: AutoModeWorkerBackend;
66
144
  mode: AutoModeMode;
145
+ secretaryAutoEnabled?: boolean;
67
146
  status: SymphonySessionStatus;
68
147
  cwd: string;
148
+ workspace?: SymphonyWorkspaceRef;
149
+ target: SymphonyDelegationTarget;
69
150
  model?: string;
151
+ supervisor?: SymphonySupervisorPolicy;
70
152
  autoModeSessionId?: string;
71
153
  dryRun?: boolean;
72
154
  exitCode?: number | null;
155
+ reconciler?: SymphonyReconcilerState;
73
156
  createdAt: string;
74
157
  updatedAt: string;
75
158
  completedAt?: string;
@@ -78,9 +161,25 @@ export interface SymphonySessionRecord extends SymphonyChatThreadRef {
78
161
  export interface SymphonyRunPlan {
79
162
  issue: SymphonyIssueRecord;
80
163
  task: string;
164
+ taskRecord: SymphonyTaskRecord;
165
+ delivery: SymphonyDeliveryRecord;
166
+ session: SymphonySessionRecord;
167
+ workers: SymphonyWorkerPlan[];
168
+ }
169
+ export interface SymphonyWorkerPlan {
170
+ task: string;
171
+ taskRecord: SymphonyTaskRecord;
81
172
  delivery: SymphonyDeliveryRecord;
82
173
  session: SymphonySessionRecord;
83
174
  }
175
+ export interface SymphonyWorkerSpec extends Partial<SymphonyDelegationTarget> {
176
+ title?: string;
177
+ objective?: string;
178
+ acceptanceCriteria?: string[];
179
+ model?: string;
180
+ supervisorIntervalMs?: number;
181
+ workspace?: Partial<SymphonyWorkspaceRef>;
182
+ }
84
183
  export interface CreateSymphonyRunPlanInput {
85
184
  objective: string;
86
185
  title?: string;
@@ -90,15 +189,28 @@ export interface CreateSymphonyRunPlanInput {
90
189
  repository?: string;
91
190
  branch?: string;
92
191
  worktree?: string;
93
- backend: AutoModeBackend;
192
+ workspaceUri?: string;
193
+ baseRevision?: string;
194
+ environment?: Partial<SymphonyWorkerEnvironmentRef>;
195
+ backend: AutoModeWorkerBackend;
94
196
  mode: AutoModeMode;
197
+ secretaryAutoEnabled?: boolean;
95
198
  model?: string;
199
+ workerModel?: string;
200
+ workerSupervisorIntervalMs?: number;
96
201
  chat?: string;
97
202
  thread?: string;
98
203
  messages?: string[];
204
+ issuer?: Partial<SymphonyIssuerRef>;
205
+ target?: Partial<SymphonyDelegationTarget>;
206
+ workers?: SymphonyWorkerSpec[];
99
207
  now?: Date;
100
208
  randomId?: string;
101
209
  }
210
+ export declare function createSymphonyIdeaUri(options?: {
211
+ now?: Date;
212
+ randomId?: string;
213
+ }): string;
102
214
  export declare function createSymphonyIssueUri(options?: {
103
215
  now?: Date;
104
216
  randomId?: string;
@@ -115,20 +227,28 @@ export declare function createSymphonySessionUri(options?: {
115
227
  now?: Date;
116
228
  randomId?: string;
117
229
  }): string;
118
- export declare function getSymphonyArchiveRelativePaths(uri: string, kind: 'issue' | 'delivery' | 'session'): {
230
+ export declare function getSymphonyArchiveRelativePaths(uri: string, kind: SymphonyResourceKind): {
119
231
  dir: string;
120
232
  file: string;
121
233
  };
122
234
  export declare function createRunPlan(input: CreateSymphonyRunPlanInput): SymphonyRunPlan;
235
+ export declare function appendSymphonyReconcilerDecision<T extends {
236
+ reconciler?: SymphonyReconcilerState;
237
+ }>(record: T, decision: ReconcileDecision | ReconcileDecisionSummary): T;
123
238
  export declare function renderSymphonyRuntimePrompt(input: {
124
239
  issue?: SymphonyIssueRecord;
125
240
  task: string;
126
241
  objective: string;
127
242
  acceptanceCriteria?: string[];
128
243
  workspace: SymphonyWorkspaceRef;
129
- backend: AutoModeBackend;
244
+ backend: AutoModeWorkerBackend;
130
245
  mode: AutoModeMode;
246
+ secretaryAutoEnabled?: boolean;
131
247
  session: string;
248
+ target?: SymphonyDelegationTarget;
249
+ issuer?: SymphonyIssuerRef;
250
+ workerIndex?: number;
251
+ workerCount?: number;
132
252
  }): string;
133
253
  export declare function formatSymphonySessionSummary(session: SymphonySessionRecord): string;
134
254
  export declare function formatSymphonyDeliverySummary(delivery: SymphonyDeliveryRecord): string;