@undefineds.co/linx 0.3.5 → 0.3.7
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.
- package/README.md +58 -23
- package/dist/generated/version.js +1 -1
- package/dist/generated/version.js.map +1 -1
- package/dist/index.js +334 -162
- package/dist/index.js.map +1 -1
- package/dist/lib/account-session.js +4 -8
- package/dist/lib/account-session.js.map +1 -1
- package/dist/lib/ai-command.js +228 -178
- package/dist/lib/ai-command.js.map +1 -1
- package/dist/lib/auto-mode/archive.js +38 -7
- package/dist/lib/auto-mode/archive.js.map +1 -1
- package/dist/lib/auto-mode/auth.js.map +1 -1
- package/dist/lib/auto-mode/display.js +71 -45
- package/dist/lib/auto-mode/display.js.map +1 -1
- package/dist/lib/auto-mode/format.js +9 -7
- package/dist/lib/auto-mode/format.js.map +1 -1
- package/dist/lib/auto-mode/hooks/claude.js +12 -2
- package/dist/lib/auto-mode/hooks/claude.js.map +1 -1
- package/dist/lib/auto-mode/hooks/codex.js +17 -7
- package/dist/lib/auto-mode/hooks/codex.js.map +1 -1
- package/dist/lib/auto-mode/hooks/index.js +28 -8
- package/dist/lib/auto-mode/hooks/index.js.map +1 -1
- package/dist/lib/auto-mode/pod-ai.js +20 -37
- package/dist/lib/auto-mode/pod-ai.js.map +1 -1
- package/dist/lib/auto-mode/pod-approval.js +124 -195
- package/dist/lib/auto-mode/pod-approval.js.map +1 -1
- package/dist/lib/auto-mode/pod-persistence.js +169 -90
- package/dist/lib/auto-mode/pod-persistence.js.map +1 -1
- package/dist/lib/auto-mode/runner.js +683 -81
- package/dist/lib/auto-mode/runner.js.map +1 -1
- package/dist/lib/auto-mode/secretary.js +186 -41
- package/dist/lib/auto-mode/secretary.js.map +1 -1
- package/dist/lib/auto-mode-command.js +32 -32
- package/dist/lib/auto-mode-command.js.map +1 -1
- package/dist/lib/chat-api.js +242 -50
- package/dist/lib/chat-api.js.map +1 -1
- package/dist/lib/codex-plugin/bridge.js +164 -17
- package/dist/lib/codex-plugin/bridge.js.map +1 -1
- package/dist/lib/codex-plugin/codex-native-proxy.js +370 -34
- package/dist/lib/codex-plugin/codex-native-proxy.js.map +1 -1
- package/dist/lib/credentials-store.js +33 -42
- package/dist/lib/credentials-store.js.map +1 -1
- package/dist/lib/linx-cloud-errors.js +61 -0
- package/dist/lib/linx-cloud-errors.js.map +1 -0
- package/dist/lib/linx-tui-contract.js +8 -5
- package/dist/lib/linx-tui-contract.js.map +1 -1
- package/dist/lib/login-command.js +9 -2
- package/dist/lib/login-command.js.map +1 -1
- package/dist/lib/models.js +3 -20
- package/dist/lib/models.js.map +1 -1
- package/dist/lib/oidc-auth.js +143 -17
- package/dist/lib/oidc-auth.js.map +1 -1
- package/dist/lib/oidc-session-storage.js +2 -6
- package/dist/lib/oidc-session-storage.js.map +1 -1
- package/dist/lib/pi-adapter/auto-input-controller.js +988 -0
- package/dist/lib/pi-adapter/auto-input-controller.js.map +1 -0
- package/dist/lib/pi-adapter/backend-command.js +2 -0
- package/dist/lib/pi-adapter/backend-command.js.map +1 -0
- package/dist/lib/pi-adapter/backend-credentials.js +80 -0
- package/dist/lib/pi-adapter/backend-credentials.js.map +1 -0
- package/dist/lib/pi-adapter/branding.js +246 -108
- package/dist/lib/pi-adapter/branding.js.map +1 -1
- package/dist/lib/pi-adapter/control-state.js +72 -0
- package/dist/lib/pi-adapter/control-state.js.map +1 -0
- package/dist/lib/pi-adapter/interactive.js +2634 -30
- package/dist/lib/pi-adapter/interactive.js.map +1 -1
- package/dist/lib/pi-adapter/pod-approval.js +382 -210
- package/dist/lib/pi-adapter/pod-approval.js.map +1 -1
- package/dist/lib/pi-adapter/pod-mirror-mapping.js +71 -17
- package/dist/lib/pi-adapter/pod-mirror-mapping.js.map +1 -1
- package/dist/lib/pi-adapter/pod-mirror.js +531 -64
- package/dist/lib/pi-adapter/pod-mirror.js.map +1 -1
- package/dist/lib/pi-adapter/pod-native.js +81 -85
- package/dist/lib/pi-adapter/pod-native.js.map +1 -1
- package/dist/lib/pi-adapter/pod-status-output.js +54 -0
- package/dist/lib/pi-adapter/pod-status-output.js.map +1 -0
- package/dist/lib/pi-adapter/runtime.js +458 -228
- package/dist/lib/pi-adapter/runtime.js.map +1 -1
- package/dist/lib/pi-adapter/session-control.js +509 -0
- package/dist/lib/pi-adapter/session-control.js.map +1 -0
- package/dist/lib/pi-adapter/session.js +35 -22
- package/dist/lib/pi-adapter/session.js.map +1 -1
- package/dist/lib/pi-adapter/stream.js +89 -32
- package/dist/lib/pi-adapter/stream.js.map +1 -1
- package/dist/lib/pi-adapter/sync-recovery.js +89 -0
- package/dist/lib/pi-adapter/sync-recovery.js.map +1 -0
- package/dist/lib/pi-adapter/web-fetch.js +13 -14
- package/dist/lib/pi-adapter/web-fetch.js.map +1 -1
- package/dist/lib/pod-chat-store.js +254 -78
- package/dist/lib/pod-chat-store.js.map +1 -1
- package/dist/lib/pod-data-session.js +156 -35
- package/dist/lib/pod-data-session.js.map +1 -1
- package/dist/lib/solid-auth-store.js +27 -0
- package/dist/lib/solid-auth-store.js.map +1 -0
- package/dist/lib/solid-auth.js +2 -4
- package/dist/lib/solid-auth.js.map +1 -1
- package/dist/lib/solid-client-credentials-login.js +100 -0
- package/dist/lib/solid-client-credentials-login.js.map +1 -0
- package/dist/lib/solid-local-store.js +31 -0
- package/dist/lib/solid-local-store.js.map +1 -0
- package/dist/lib/symphony/archive.js +328 -18
- package/dist/lib/symphony/archive.js.map +1 -1
- package/dist/lib/symphony/pod-projection.js +2222 -0
- package/dist/lib/symphony/pod-projection.js.map +1 -0
- package/dist/lib/symphony-command.js +602 -178
- package/dist/lib/symphony-command.js.map +1 -1
- package/dist/lib/sync-checkpoint-store.js +74 -0
- package/dist/lib/sync-checkpoint-store.js.map +1 -0
- package/dist/skills/symphony/SKILL.md +665 -0
- package/package.json +15 -9
- package/vendor/agent-runtime/dist/agent-runtime.d.ts +137 -0
- package/vendor/agent-runtime/dist/agent-runtime.js +211 -0
- package/vendor/agent-runtime/dist/auto-mode.d.ts +78 -13
- package/vendor/agent-runtime/dist/auto-mode.js +288 -31
- package/vendor/agent-runtime/dist/control-plane.d.ts +28 -0
- package/vendor/agent-runtime/dist/control-plane.js +79 -0
- package/vendor/agent-runtime/dist/file-sync.d.ts +157 -0
- package/vendor/agent-runtime/dist/file-sync.js +314 -0
- package/vendor/agent-runtime/dist/index.d.ts +7 -0
- package/vendor/agent-runtime/dist/index.js +7 -0
- package/vendor/agent-runtime/dist/reconciler.d.ts +117 -0
- package/vendor/agent-runtime/dist/reconciler.js +361 -0
- package/vendor/agent-runtime/dist/symphony.d.ts +128 -8
- package/vendor/agent-runtime/dist/symphony.js +362 -57
- package/vendor/agent-runtime/dist/sync.d.ts +271 -0
- package/vendor/agent-runtime/dist/sync.js +550 -0
- package/vendor/agent-runtime/dist/thread-reconciler-controller.d.ts +58 -0
- package/vendor/agent-runtime/dist/thread-reconciler-controller.js +137 -0
- package/vendor/agent-runtime/dist/turn-controller.js +2 -2
- package/vendor/agent-runtime/dist/wake-scheduler.d.ts +67 -0
- package/vendor/agent-runtime/dist/wake-scheduler.js +194 -0
- package/vendor/agent-runtime/package.json +8 -1
- package/vendor/pi-web-access/CHANGELOG.md +387 -0
- package/vendor/pi-web-access/LICENSE +21 -0
- package/vendor/pi-web-access/README.md +352 -0
- package/vendor/pi-web-access/activity.ts +101 -0
- package/vendor/pi-web-access/banner.png +0 -0
- package/vendor/pi-web-access/chrome-cookies.ts +322 -0
- package/vendor/pi-web-access/code-search.ts +107 -0
- package/vendor/pi-web-access/curator-page.ts +3359 -0
- package/vendor/pi-web-access/curator-server.ts +605 -0
- package/vendor/pi-web-access/exa.ts +520 -0
- package/vendor/pi-web-access/extract.ts +641 -0
- package/vendor/pi-web-access/gemini-api.ts +112 -0
- package/vendor/pi-web-access/gemini-search.ts +361 -0
- package/vendor/pi-web-access/gemini-url-context.ts +126 -0
- package/vendor/pi-web-access/gemini-web-config.ts +52 -0
- package/vendor/pi-web-access/gemini-web.ts +396 -0
- package/vendor/pi-web-access/github-api.ts +196 -0
- package/vendor/pi-web-access/github-extract.ts +634 -0
- package/vendor/pi-web-access/index.ts +2346 -0
- package/vendor/pi-web-access/package.json +45 -0
- package/vendor/pi-web-access/pdf-extract.ts +192 -0
- package/vendor/pi-web-access/perplexity.ts +195 -0
- package/vendor/pi-web-access/pi-web-fetch-demo.mp4 +0 -0
- package/vendor/pi-web-access/rsc-extract.ts +338 -0
- package/vendor/pi-web-access/skills/librarian/SKILL.md +195 -0
- package/vendor/pi-web-access/storage.ts +72 -0
- package/vendor/pi-web-access/summary-review.ts +276 -0
- package/vendor/pi-web-access/test/gemini-web-cookie-opt-in.test.mjs +41 -0
- package/vendor/pi-web-access/test/pdf-extract.test.mjs +95 -0
- package/vendor/pi-web-access/utils.ts +44 -0
- package/vendor/pi-web-access/video-extract.ts +378 -0
- package/vendor/pi-web-access/youtube-extract.ts +310 -0
- package/dist/lib/pi-adapter/auth.js +0 -68
- package/dist/lib/pi-adapter/auth.js.map +0 -1
- package/dist/lib/pi-adapter/pod-tools.js +0 -140
- package/dist/lib/pi-adapter/pod-tools.js.map +0 -1
- package/dist/skills/drizzle-solid/SKILL.md +0 -340
- package/dist/skills/pod-storage/SKILL.md +0 -100
- package/dist/skills/solid-modeling/SKILL.md +0 -274
- 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 {
|
|
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: '
|
|
47
|
-
targetBackend:
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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;
|