@coffer-org/plugin-orchestrator 1.3.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/runtime/db.d.ts +0 -1
- package/dist/runtime/index.d.ts +4 -1
- package/dist/runtime/index.js +2 -0
- package/dist/runtime/live-message.d.ts +14 -0
- package/dist/runtime/live-message.js +83 -0
- package/dist/runtime/pipeline.d.ts +4 -4
- package/dist/runtime/pipeline.js +74 -95
- package/dist/runtime/system-assembly.d.ts +6 -0
- package/dist/runtime/system-assembly.js +7 -0
- package/dist/runtime/types.d.ts +32 -16
- package/dist/schema.js +120 -43
- package/package.json +4 -4
package/dist/index.js
CHANGED
package/dist/runtime/db.d.ts
CHANGED
package/dist/runtime/index.d.ts
CHANGED
|
@@ -2,5 +2,8 @@ import type { PluginHooks } from '@coffer-org/server/plugin-hooks';
|
|
|
2
2
|
export { handleIncoming } from './pipeline.ts';
|
|
3
3
|
export type { PipelineDeps, RunAgentFn } from './pipeline.ts';
|
|
4
4
|
export { buildPolicy, loadGatePolicy } from './config.ts';
|
|
5
|
-
export
|
|
5
|
+
export { makeLiveChannel, plainRender } from './live-message.ts';
|
|
6
|
+
export type { LiveChannelOps, LiveChannelOpts, RenderFn } from './live-message.ts';
|
|
7
|
+
export { chunk } from './format.ts';
|
|
8
|
+
export type { Connector, IncomingConversation, GatePolicy, ReplyContext, ReplyPayload, ReplyChannel, ConvMessage, SystemLayer, AgentRequest, AgentResult, } from './types.ts';
|
|
6
9
|
export declare const serverHooks: PluginHooks;
|
package/dist/runtime/index.js
CHANGED
|
@@ -2,6 +2,8 @@ import { openLogDb } from "./db.js";
|
|
|
2
2
|
import { setLogDb } from "./pipeline.js";
|
|
3
3
|
export { handleIncoming } from "./pipeline.js";
|
|
4
4
|
export { buildPolicy, loadGatePolicy } from "./config.js";
|
|
5
|
+
export { makeLiveChannel, plainRender } from "./live-message.js";
|
|
6
|
+
export { chunk } from "./format.js";
|
|
5
7
|
let db;
|
|
6
8
|
export const serverHooks = {
|
|
7
9
|
init: () => { db = openLogDb(); setLogDb(db); },
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ReplyChannel, ReplyPayload } from './types.ts';
|
|
2
|
+
export interface LiveChannelOps {
|
|
3
|
+
send(text: string): Promise<string | null>;
|
|
4
|
+
edit(msgId: string, text: string): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
export type RenderFn = (r: ReplyPayload) => string[];
|
|
7
|
+
export interface LiveChannelOpts {
|
|
8
|
+
ops: LiveChannelOps;
|
|
9
|
+
throttleMs: number;
|
|
10
|
+
render: RenderFn;
|
|
11
|
+
maxLength: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function plainRender(max: number): RenderFn;
|
|
14
|
+
export declare function makeLiveChannel(o: LiveChannelOpts): ReplyChannel;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { chunk } from "./format.js";
|
|
2
|
+
import { getLogger } from '@coffer-org/sdk/logger';
|
|
3
|
+
const log = getLogger('orchestrator');
|
|
4
|
+
export function plainRender(max) {
|
|
5
|
+
return (r) => chunk((r.text ?? '').trim() || '⚠️ the agent returned no response', max);
|
|
6
|
+
}
|
|
7
|
+
async function swallow(fn, fallback, label) {
|
|
8
|
+
try {
|
|
9
|
+
return await fn();
|
|
10
|
+
}
|
|
11
|
+
catch (err) {
|
|
12
|
+
log.error(`live-message ${label}: ${err instanceof Error ? err.message : String(err)}`);
|
|
13
|
+
return fallback;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function makeLiveChannel(o) {
|
|
17
|
+
let msgId = null;
|
|
18
|
+
let pending = '';
|
|
19
|
+
let lastSent = '';
|
|
20
|
+
let busy = false;
|
|
21
|
+
let closed = false;
|
|
22
|
+
let gen = 0;
|
|
23
|
+
let inFlight = Promise.resolve();
|
|
24
|
+
const timer = setInterval(() => {
|
|
25
|
+
if (closed || busy)
|
|
26
|
+
return;
|
|
27
|
+
const t = pending.slice(0, o.maxLength);
|
|
28
|
+
if (!t || t === lastSent)
|
|
29
|
+
return;
|
|
30
|
+
busy = true;
|
|
31
|
+
const myGen = gen;
|
|
32
|
+
if (!msgId) {
|
|
33
|
+
inFlight = o.ops.send(t)
|
|
34
|
+
.then((id) => { if (gen === myGen) {
|
|
35
|
+
msgId = id;
|
|
36
|
+
lastSent = t;
|
|
37
|
+
} })
|
|
38
|
+
.catch((err) => { log.error(`live-message send: ${err instanceof Error ? err.message : String(err)}`); })
|
|
39
|
+
.finally(() => { busy = false; });
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const id = msgId;
|
|
43
|
+
inFlight = o.ops.edit(id, t)
|
|
44
|
+
.then(() => { if (gen === myGen)
|
|
45
|
+
lastSent = t; })
|
|
46
|
+
.catch((err) => { log.error(`live-message edit: ${err instanceof Error ? err.message : String(err)}`); })
|
|
47
|
+
.finally(() => { busy = false; });
|
|
48
|
+
}, o.throttleMs);
|
|
49
|
+
if (typeof timer.unref === 'function')
|
|
50
|
+
timer.unref();
|
|
51
|
+
return {
|
|
52
|
+
update(text) {
|
|
53
|
+
pending = text;
|
|
54
|
+
},
|
|
55
|
+
segment() {
|
|
56
|
+
gen++;
|
|
57
|
+
msgId = null;
|
|
58
|
+
pending = '';
|
|
59
|
+
lastSent = '';
|
|
60
|
+
},
|
|
61
|
+
async finish(r) {
|
|
62
|
+
closed = true;
|
|
63
|
+
clearInterval(timer);
|
|
64
|
+
await inFlight;
|
|
65
|
+
const parts = o.render(r);
|
|
66
|
+
let last = null;
|
|
67
|
+
const [head, ...rest] = parts;
|
|
68
|
+
if (msgId && head !== undefined) {
|
|
69
|
+
const id = msgId;
|
|
70
|
+
await swallow(() => o.ops.edit(id, head), undefined, 'edit(final)');
|
|
71
|
+
last = id;
|
|
72
|
+
}
|
|
73
|
+
else if (head !== undefined) {
|
|
74
|
+
last = await swallow(() => o.ops.send(head), null, 'send(final)');
|
|
75
|
+
}
|
|
76
|
+
for (const p of rest) {
|
|
77
|
+
const id = await swallow(() => o.ops.send(p), null, 'send(overflow)');
|
|
78
|
+
last = id ?? last;
|
|
79
|
+
}
|
|
80
|
+
return last;
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { runAgent } from '@coffer-org/plugin-agent/runtime';
|
|
2
|
-
import type { Connector,
|
|
1
|
+
import { runAgent } from '@coffer-org/plugin-claude-agent/runtime';
|
|
2
|
+
import type { Connector, IncomingConversation, GatePolicy } from './types.ts';
|
|
3
3
|
import type { LogDb } from './db.ts';
|
|
4
4
|
export declare function setLogDb(db: LogDb | undefined): void;
|
|
5
5
|
export type RunAgentFn = typeof runAgent;
|
|
6
6
|
export interface PipelineDeps {
|
|
7
7
|
runAgent?: RunAgentFn;
|
|
8
8
|
logDb?: LogDb | null;
|
|
9
|
-
throttleMs?: number;
|
|
10
9
|
policy?: GatePolicy;
|
|
10
|
+
agentBase?: () => Promise<string>;
|
|
11
11
|
}
|
|
12
|
-
export declare function handleIncoming(connector: Connector,
|
|
12
|
+
export declare function handleIncoming(connector: Connector, conversation: IncomingConversation, deps?: PipelineDeps): Promise<void>;
|
package/dist/runtime/pipeline.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import { runAgent } from '@coffer-org/plugin-agent/runtime';
|
|
2
|
-
import { chunk } from "./format.js";
|
|
1
|
+
import { runAgent, agentSystemBase } from '@coffer-org/plugin-claude-agent/runtime';
|
|
3
2
|
import { join } from 'node:path';
|
|
4
|
-
import { loadThreads, saveThreads, resolveParent, getSession, recordSession, pruneThreads, } from "./threads.js";
|
|
5
3
|
import { loadAllowed, saveAllowed, isAllowed, addAllowed, makeThrottle } from "./allow.js";
|
|
6
4
|
import { loadGatePolicy } from "./config.js";
|
|
5
|
+
import { buildSystem } from "./system-assembly.js";
|
|
7
6
|
import { getLogger } from '@coffer-org/sdk/logger';
|
|
8
7
|
const log = getLogger('orchestrator');
|
|
9
|
-
const DEFAULT_STREAM_THROTTLE_MS = 2000;
|
|
10
8
|
const stateDir = () => process.env['ORCHESTRATOR_STATE_DIR']
|
|
11
9
|
?? join(new URL('../../runtime/state', import.meta.url).pathname);
|
|
12
10
|
let logDb;
|
|
@@ -20,6 +18,17 @@ function passThrottle(connectorId) {
|
|
|
20
18
|
}
|
|
21
19
|
return t;
|
|
22
20
|
}
|
|
21
|
+
let cachedBase;
|
|
22
|
+
function cachedAgentBase() { return (cachedBase ??= agentSystemBase()); }
|
|
23
|
+
function openChannel(connector, chatId, ctx) {
|
|
24
|
+
try {
|
|
25
|
+
return connector.reply(chatId, ctx);
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
log.error(`connector error in reply: ${err instanceof Error ? err.message : String(err)}`);
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
23
32
|
async function safeCall(fn, fallback, label) {
|
|
24
33
|
try {
|
|
25
34
|
return await fn();
|
|
@@ -29,115 +38,85 @@ async function safeCall(fn, fallback, label) {
|
|
|
29
38
|
return fallback;
|
|
30
39
|
}
|
|
31
40
|
}
|
|
32
|
-
export async function handleIncoming(connector,
|
|
41
|
+
export async function handleIncoming(connector, conversation, deps) {
|
|
33
42
|
const agent = deps?.runAgent ?? runAgent;
|
|
34
43
|
const db = deps && 'logDb' in deps ? deps.logDb : logDb;
|
|
35
|
-
const throttleMs = deps?.throttleMs ?? DEFAULT_STREAM_THROTTLE_MS;
|
|
36
44
|
const policy = deps?.policy ?? await loadGatePolicy();
|
|
37
|
-
const
|
|
45
|
+
const agentBase = deps?.agentBase ?? cachedAgentBase;
|
|
46
|
+
const { connectorId, chatId, sender, messages } = conversation;
|
|
47
|
+
const last = messages[messages.length - 1];
|
|
48
|
+
if (!last || last.role !== 'user')
|
|
49
|
+
return;
|
|
50
|
+
const incomingMsgId = last.msgId;
|
|
38
51
|
const dir = stateDir();
|
|
39
|
-
const allowFile = join(dir, `${
|
|
40
|
-
const threadsFile = join(dir, `${connector.id}.threads.json`);
|
|
52
|
+
const allowFile = join(dir, `${connectorId}.allowed.json`);
|
|
41
53
|
if (policy.accessPassword) {
|
|
42
54
|
let allow = loadAllowed(allowFile);
|
|
43
|
-
if (!isAllowed(allow,
|
|
44
|
-
if (
|
|
45
|
-
allow = addAllowed(allow,
|
|
55
|
+
if (!isAllowed(allow, sender.id)) {
|
|
56
|
+
if (last.content.trim() === policy.accessPassword) {
|
|
57
|
+
allow = addAllowed(allow, sender.id, Date.now());
|
|
46
58
|
saveAllowed(allowFile, allow);
|
|
47
|
-
|
|
59
|
+
const ch = openChannel(connector, chatId, { parentMsgId: incomingMsgId });
|
|
60
|
+
if (ch)
|
|
61
|
+
await safeCall(() => ch.finish({ text: '✅ Access granted. Send your requests.', reasoning: null }), null, 'finish(enroll)');
|
|
48
62
|
}
|
|
49
|
-
else if (passThrottle(
|
|
50
|
-
|
|
63
|
+
else if (passThrottle(connectorId)(sender.id)) {
|
|
64
|
+
const ch = openChannel(connector, chatId, { parentMsgId: incomingMsgId });
|
|
65
|
+
if (ch)
|
|
66
|
+
await safeCall(() => ch.finish({ text: '🔒 Access locked. Send the password to gain access.', reasoning: null }), null, 'finish(locked)');
|
|
51
67
|
}
|
|
52
68
|
return;
|
|
53
69
|
}
|
|
54
70
|
}
|
|
55
|
-
if (policy.triggerPrefix && !
|
|
71
|
+
if (policy.triggerPrefix && !last.content.toLowerCase().startsWith(policy.triggerPrefix.toLowerCase()))
|
|
56
72
|
return;
|
|
57
|
-
const queryText = policy.triggerPrefix ?
|
|
73
|
+
const queryText = policy.triggerPrefix ? last.content.slice(policy.triggerPrefix.length).trim() : last.content.trim();
|
|
58
74
|
if (!queryText)
|
|
59
75
|
return;
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
76
|
+
const agentMessages = policy.triggerPrefix
|
|
77
|
+
? messages.map((m, i) => (i === messages.length - 1 ? { ...m, content: queryText } : m))
|
|
78
|
+
: messages;
|
|
79
|
+
const base = await agentBase();
|
|
80
|
+
const system = buildSystem({
|
|
81
|
+
base,
|
|
82
|
+
channelSystem: conversation.channelSystem,
|
|
83
|
+
volatileSystem: conversation.volatileSystem,
|
|
84
|
+
});
|
|
85
|
+
db?.logTurn({ connector: connectorId, chatId, userId: sender.id, role: 'user', text: queryText, tokensIn: null, tokensOut: null, ms: null });
|
|
65
86
|
const startedAt = Date.now();
|
|
66
|
-
const
|
|
67
|
-
|
|
87
|
+
const ch = openChannel(connector, chatId, { parentMsgId: incomingMsgId });
|
|
88
|
+
if (!ch)
|
|
89
|
+
return;
|
|
68
90
|
let result;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
:
|
|
74
|
-
|
|
75
|
-
let editPromise = Promise.resolve();
|
|
76
|
-
const timer = setInterval(() => {
|
|
77
|
-
if (closed || editing)
|
|
78
|
-
return;
|
|
79
|
-
const t = pending.slice(0, max);
|
|
80
|
-
if (!t || t === lastEdited)
|
|
81
|
-
return;
|
|
82
|
-
editing = true;
|
|
83
|
-
if (!placeholderId) {
|
|
84
|
-
editPromise = safeCall(() => connector.sendMessage(chatId, t), null, 'sendMessage(stream-create)')
|
|
85
|
-
.then((s) => { placeholderId = s?.msgId ?? null; lastEdited = t; })
|
|
86
|
-
.finally(() => { editing = false; });
|
|
87
|
-
return;
|
|
91
|
+
try {
|
|
92
|
+
result = await agent({
|
|
93
|
+
system,
|
|
94
|
+
messages: agentMessages,
|
|
95
|
+
onDelta: (acc) => { try {
|
|
96
|
+
ch.update(acc);
|
|
88
97
|
}
|
|
89
|
-
|
|
90
|
-
.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
else {
|
|
106
|
-
const stopTyping = connector.capabilities.typing && connector.startTyping
|
|
107
|
-
? await safeCall(async () => connector.startTyping(chatId), undefined, 'startTyping')
|
|
108
|
-
: undefined;
|
|
109
|
-
try {
|
|
110
|
-
result = await agent({ prompt: queryText, sessionId: parentSession });
|
|
111
|
-
if (result.text == null && parentSession)
|
|
112
|
-
result = await agent({ prompt: queryText, sessionId: null });
|
|
113
|
-
}
|
|
114
|
-
finally {
|
|
115
|
-
stopTyping?.();
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
let botMsgId = null;
|
|
119
|
-
const out = result.text ?? '⚠️ the agent returned no response';
|
|
120
|
-
const parts = chunk(out, max);
|
|
121
|
-
if (canStream && placeholderId) {
|
|
122
|
-
await safeCall(() => connector.editMessage(chatId, placeholderId, parts[0]), undefined, 'editMessage(final)');
|
|
123
|
-
botMsgId = placeholderId;
|
|
124
|
-
for (const p of parts.slice(1)) {
|
|
125
|
-
const s = await safeCall(() => connector.sendMessage(chatId, p), null, 'sendMessage(overflow)');
|
|
126
|
-
botMsgId = s?.msgId ?? botMsgId;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
for (const p of parts) {
|
|
131
|
-
const s = await safeCall(() => connector.sendMessage(chatId, p), null, 'sendMessage(deliver)');
|
|
132
|
-
botMsgId = s?.msgId ?? botMsgId;
|
|
133
|
-
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
log.error(`connector error in update: ${err instanceof Error ? err.message : String(err)}`);
|
|
100
|
+
} },
|
|
101
|
+
onReasoning: (acc) => { try {
|
|
102
|
+
ch.updateReasoning?.(acc);
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
log.error(`connector error in updateReasoning: ${err instanceof Error ? err.message : String(err)}`);
|
|
106
|
+
} },
|
|
107
|
+
onSegment: () => { try {
|
|
108
|
+
ch.segment();
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
log.error(`connector error in segment: ${err instanceof Error ? err.message : String(err)}`);
|
|
112
|
+
} },
|
|
113
|
+
});
|
|
134
114
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if (result.sessionId) {
|
|
138
|
-
const incomingMsgId = replyToId ?? String(now);
|
|
139
|
-
threads = recordSession(threads, { msgId: incomingMsgId, botMsgId, sessionId: result.sessionId, now });
|
|
140
|
-
threads = pruneThreads(threads, now, 7);
|
|
141
|
-
saveThreads(threadsFile, threads);
|
|
115
|
+
catch (err) {
|
|
116
|
+
log.error(`agent error: ${err instanceof Error ? err.message : String(err)}`);
|
|
142
117
|
}
|
|
118
|
+
const botMsgId = await safeCall(() => ch.finish({ text: result?.text ?? null, reasoning: result?.reasoning ?? null }), null, 'finish');
|
|
119
|
+
if (result?.text)
|
|
120
|
+
db?.logTurn({ connector: connectorId, chatId, userId: sender.id, role: 'assistant', text: result.text, tokensIn: result.tokensIn, tokensOut: result.tokensOut, ms: Date.now() - startedAt });
|
|
121
|
+
await safeCall(() => connector.recordAssistant({ parentMsgId: incomingMsgId, botMsgId, text: result?.text ?? '', reasoning: result?.reasoning ?? null }), undefined, 'recordAssistant');
|
|
143
122
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export function buildSystem(input) {
|
|
2
|
+
const text = [input.base, input.channelSystem].filter(Boolean).join('\n\n');
|
|
3
|
+
const layers = [{ text, stable: true }];
|
|
4
|
+
if (input.volatileSystem?.trim())
|
|
5
|
+
layers.push({ text: input.volatileSystem, stable: false });
|
|
6
|
+
return layers;
|
|
7
|
+
}
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -1,22 +1,38 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
export type { ConvMessage, SystemLayer, AgentRequest, AgentResult } from '@coffer-org/plugin-claude-agent/runtime';
|
|
2
|
+
import type { ConvMessage } from '@coffer-org/plugin-claude-agent/runtime';
|
|
3
|
+
export interface IncomingConversation {
|
|
4
|
+
connectorId: string;
|
|
5
|
+
chatId: string;
|
|
6
|
+
channelSystem?: string;
|
|
7
|
+
volatileSystem?: string;
|
|
8
|
+
sender: {
|
|
9
|
+
id: string;
|
|
10
|
+
displayName?: string;
|
|
11
|
+
};
|
|
12
|
+
messages: ConvMessage[];
|
|
13
|
+
}
|
|
14
|
+
export interface ReplyContext {
|
|
15
|
+
parentMsgId: string | null;
|
|
16
|
+
}
|
|
17
|
+
export interface ReplyPayload {
|
|
18
|
+
text: string | null;
|
|
19
|
+
reasoning: string | null;
|
|
20
|
+
}
|
|
21
|
+
export interface ReplyChannel {
|
|
22
|
+
update(text: string): void;
|
|
23
|
+
updateReasoning?(acc: string): void;
|
|
24
|
+
segment(): void;
|
|
25
|
+
finish(r: ReplyPayload): Promise<string | null>;
|
|
5
26
|
}
|
|
6
27
|
export interface Connector {
|
|
7
28
|
id: string;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
export interface IncomingPayload {
|
|
16
|
-
chatId: string;
|
|
17
|
-
userId: string;
|
|
18
|
-
text: string;
|
|
19
|
-
replyToId: string | null;
|
|
29
|
+
reply(chatId: string, ctx: ReplyContext): ReplyChannel;
|
|
30
|
+
recordAssistant(m: {
|
|
31
|
+
parentMsgId: string | null;
|
|
32
|
+
botMsgId: string | null;
|
|
33
|
+
text: string;
|
|
34
|
+
reasoning: string | null;
|
|
35
|
+
}): Promise<void>;
|
|
20
36
|
}
|
|
21
37
|
export interface GatePolicy {
|
|
22
38
|
accessPassword: string;
|
package/dist/schema.js
CHANGED
|
@@ -154,7 +154,10 @@ function assignProp(target, prop, value) {
|
|
|
154
154
|
}
|
|
155
155
|
function mergeDefs(...defs) {
|
|
156
156
|
const mergedDescriptors = {};
|
|
157
|
-
for (const def of defs)
|
|
157
|
+
for (const def of defs) {
|
|
158
|
+
const descriptors = Object.getOwnPropertyDescriptors(def);
|
|
159
|
+
Object.assign(mergedDescriptors, descriptors);
|
|
160
|
+
}
|
|
158
161
|
return Object.defineProperties({}, mergedDescriptors);
|
|
159
162
|
}
|
|
160
163
|
function esc(str) {
|
|
@@ -476,7 +479,7 @@ var _parse = (_Err) => (schema, value, _ctx, _params) => {
|
|
|
476
479
|
}, ctx);
|
|
477
480
|
if (result instanceof Promise) throw new $ZodAsyncError();
|
|
478
481
|
if (result.issues.length) {
|
|
479
|
-
const e = new (_params?.Err ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
|
|
482
|
+
const e = new ((_params?.Err) ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
|
|
480
483
|
captureStackTrace(e, _params?.callee);
|
|
481
484
|
throw e;
|
|
482
485
|
}
|
|
@@ -493,7 +496,7 @@ var _parseAsync = (_Err) => async (schema, value, _ctx, params) => {
|
|
|
493
496
|
}, ctx);
|
|
494
497
|
if (result instanceof Promise) result = await result;
|
|
495
498
|
if (result.issues.length) {
|
|
496
|
-
const e = new (params?.Err ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
|
|
499
|
+
const e = new ((params?.Err) ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
|
|
497
500
|
captureStackTrace(e, params?.callee);
|
|
498
501
|
throw e;
|
|
499
502
|
}
|
|
@@ -1589,13 +1592,13 @@ var $ZodObject = /*@__PURE__*/ $constructor("$ZodObject", (inst, def) => {
|
|
|
1589
1592
|
}
|
|
1590
1593
|
return propValues;
|
|
1591
1594
|
});
|
|
1592
|
-
const isObject$
|
|
1595
|
+
const isObject$2 = isObject;
|
|
1593
1596
|
const catchall = def.catchall;
|
|
1594
1597
|
let value;
|
|
1595
1598
|
inst._zod.parse = (payload, ctx) => {
|
|
1596
1599
|
value ?? (value = _normalized.value);
|
|
1597
1600
|
const input = payload.value;
|
|
1598
|
-
if (!isObject$
|
|
1601
|
+
if (!isObject$2(input)) {
|
|
1599
1602
|
payload.issues.push({
|
|
1600
1603
|
expected: "object",
|
|
1601
1604
|
code: "invalid_type",
|
|
@@ -1718,7 +1721,7 @@ var $ZodObjectJIT = /*@__PURE__*/ $constructor("$ZodObjectJIT", (inst, def) => {
|
|
|
1718
1721
|
return (payload, ctx) => fn(shape, payload, ctx);
|
|
1719
1722
|
};
|
|
1720
1723
|
let fastpass;
|
|
1721
|
-
const isObject$
|
|
1724
|
+
const isObject$1 = isObject;
|
|
1722
1725
|
const jit = !globalConfig.jitless;
|
|
1723
1726
|
const fastEnabled = jit && allowsEval.value;
|
|
1724
1727
|
const catchall = def.catchall;
|
|
@@ -1726,7 +1729,7 @@ var $ZodObjectJIT = /*@__PURE__*/ $constructor("$ZodObjectJIT", (inst, def) => {
|
|
|
1726
1729
|
inst._zod.parse = (payload, ctx) => {
|
|
1727
1730
|
value ?? (value = _normalized.value);
|
|
1728
1731
|
const input = payload.value;
|
|
1729
|
-
if (!isObject$
|
|
1732
|
+
if (!isObject$1(input)) {
|
|
1730
1733
|
payload.issues.push({
|
|
1731
1734
|
expected: "object",
|
|
1732
1735
|
code: "invalid_type",
|
|
@@ -1945,7 +1948,7 @@ var $ZodOptional = /*@__PURE__*/ $constructor("$ZodOptional", (inst, def) => {
|
|
|
1945
1948
|
inst._zod.optin = "optional";
|
|
1946
1949
|
inst._zod.optout = "optional";
|
|
1947
1950
|
defineLazy(inst._zod, "values", () => {
|
|
1948
|
-
return def.innerType._zod.values ? new Set([...def.innerType._zod.values, void 0]) : void 0;
|
|
1951
|
+
return def.innerType._zod.values ? /* @__PURE__ */ new Set([...def.innerType._zod.values, void 0]) : void 0;
|
|
1949
1952
|
});
|
|
1950
1953
|
defineLazy(inst._zod, "pattern", () => {
|
|
1951
1954
|
const pattern = def.innerType._zod.pattern;
|
|
@@ -1979,7 +1982,7 @@ var $ZodNullable = /*@__PURE__*/ $constructor("$ZodNullable", (inst, def) => {
|
|
|
1979
1982
|
return pattern ? new RegExp(`^(${cleanRegex(pattern.source)}|null)$`) : void 0;
|
|
1980
1983
|
});
|
|
1981
1984
|
defineLazy(inst._zod, "values", () => {
|
|
1982
|
-
return def.innerType._zod.values ? new Set([...def.innerType._zod.values, null]) : void 0;
|
|
1985
|
+
return def.innerType._zod.values ? /* @__PURE__ */ new Set([...def.innerType._zod.values, null]) : void 0;
|
|
1983
1986
|
});
|
|
1984
1987
|
inst._zod.parse = (payload, ctx) => {
|
|
1985
1988
|
if (payload.value === null) return payload;
|
|
@@ -4587,7 +4590,7 @@ function password(raw) {
|
|
|
4587
4590
|
* Internal API-token list — keyValue-shaped collection (name + write-only
|
|
4588
4591
|
* token + timestamps), custom renderer (`kind:'internalApiToken'`, own
|
|
4589
4592
|
* create/revoke UI — same trick as url()/perWeekday()). "Internal" = not a
|
|
4590
|
-
* general-purpose field type for plugin
|
|
4593
|
+
* general-purpose field type for plugin shelves, only for the core account
|
|
4591
4594
|
* settings page. `token` is `kind:'password'` so maskSecrets/preserveTree
|
|
4592
4595
|
* already mask/preserve it for free.
|
|
4593
4596
|
*/
|
|
@@ -4606,6 +4609,25 @@ function internalApiToken(o) {
|
|
|
4606
4609
|
]
|
|
4607
4610
|
});
|
|
4608
4611
|
}
|
|
4612
|
+
/**
|
|
4613
|
+
* Internal "connected apps" list — the OAuth clients (claude.ai & co) the user
|
|
4614
|
+
* has authorized for MCP access. Same "internal" caveat and custom-renderer
|
|
4615
|
+
* trick as internalApiToken(): read-only rows + a revoke action, never part of
|
|
4616
|
+
* the parent form's save.
|
|
4617
|
+
*/
|
|
4618
|
+
function internalOauthGrants(o) {
|
|
4619
|
+
return group({
|
|
4620
|
+
key: o.key,
|
|
4621
|
+
label: o.label ?? o.key,
|
|
4622
|
+
multiple: true,
|
|
4623
|
+
view: { kind: "internalOauthGrants" },
|
|
4624
|
+
fields: [
|
|
4625
|
+
string({ key: "clientName" }),
|
|
4626
|
+
string({ key: "createdAt" }),
|
|
4627
|
+
string({ key: "lastUsedAt" })
|
|
4628
|
+
]
|
|
4629
|
+
});
|
|
4630
|
+
}
|
|
4609
4631
|
var SLUG_RE = /^[a-z0-9-]+$/;
|
|
4610
4632
|
function slug(raw) {
|
|
4611
4633
|
const o = normalizeOpts(raw);
|
|
@@ -4686,7 +4708,7 @@ var TEL_RE = /^\+?[\d\s()-]{4,}$/;
|
|
|
4686
4708
|
/** Loose URL: будь-який scheme:// АБО host-з-крапкою (+опц. порт/шлях). Без пробілів. */
|
|
4687
4709
|
var LINK_RE = /^([a-z][a-z0-9+.-]*:\/\/\S+|[\w-]+(\.[\w-]+)+(:\d+)?(\/\S*)?)$/i;
|
|
4688
4710
|
/** CSS named colors (CSS Color Module L4) — для f.colorname. */
|
|
4689
|
-
var CSS_COLOR_NAMES = new Set([
|
|
4711
|
+
var CSS_COLOR_NAMES = /* @__PURE__ */ new Set([
|
|
4690
4712
|
"aliceblue",
|
|
4691
4713
|
"antiquewhite",
|
|
4692
4714
|
"aqua",
|
|
@@ -5035,7 +5057,8 @@ var presets = {
|
|
|
5035
5057
|
weight,
|
|
5036
5058
|
dimensions,
|
|
5037
5059
|
country,
|
|
5038
|
-
internalApiToken
|
|
5060
|
+
internalApiToken,
|
|
5061
|
+
internalOauthGrants
|
|
5039
5062
|
};
|
|
5040
5063
|
//#endregion
|
|
5041
5064
|
//#region ../../node_modules/iso-639-1/src/data.js
|
|
@@ -5147,7 +5170,7 @@ var require_data = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
5147
5170
|
},
|
|
5148
5171
|
cs: {
|
|
5149
5172
|
name: "Czech",
|
|
5150
|
-
nativeName: "
|
|
5173
|
+
nativeName: "čeština"
|
|
5151
5174
|
},
|
|
5152
5175
|
cu: {
|
|
5153
5176
|
name: "Old Church Slavonic",
|
|
@@ -5611,7 +5634,7 @@ var require_data = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
5611
5634
|
},
|
|
5612
5635
|
sk: {
|
|
5613
5636
|
name: "Slovak",
|
|
5614
|
-
nativeName: "
|
|
5637
|
+
nativeName: "slovenčtina"
|
|
5615
5638
|
},
|
|
5616
5639
|
sl: {
|
|
5617
5640
|
name: "Slovenian",
|
|
@@ -5862,7 +5885,7 @@ function group(o) {
|
|
|
5862
5885
|
required: o.required,
|
|
5863
5886
|
unique: r.unique,
|
|
5864
5887
|
label: o.label,
|
|
5865
|
-
icon:
|
|
5888
|
+
icon: o.icon,
|
|
5866
5889
|
display: v.display ?? "wrap",
|
|
5867
5890
|
kind: v.kind,
|
|
5868
5891
|
fixed: r.fixed,
|
|
@@ -5873,11 +5896,9 @@ function group(o) {
|
|
|
5873
5896
|
function row(o) {
|
|
5874
5897
|
return group({
|
|
5875
5898
|
label: o.label,
|
|
5899
|
+
icon: o.icon,
|
|
5876
5900
|
fields: o.fields,
|
|
5877
|
-
view: {
|
|
5878
|
-
...o.view,
|
|
5879
|
-
display: "scroll"
|
|
5880
|
-
}
|
|
5901
|
+
view: { display: "scroll" }
|
|
5881
5902
|
});
|
|
5882
5903
|
}
|
|
5883
5904
|
/** Tabular collection (array of rows → <table>, aligned by columns). Sugar. */
|
|
@@ -5885,14 +5906,12 @@ function table(o) {
|
|
|
5885
5906
|
return group({
|
|
5886
5907
|
key: o.key,
|
|
5887
5908
|
label: o.label,
|
|
5909
|
+
icon: o.icon,
|
|
5888
5910
|
fields: o.fields,
|
|
5889
5911
|
multiple: true,
|
|
5890
5912
|
required: o.required,
|
|
5891
5913
|
rules: o.rules,
|
|
5892
|
-
view: {
|
|
5893
|
-
...o.view,
|
|
5894
|
-
display: "table"
|
|
5895
|
-
}
|
|
5914
|
+
view: { display: "table" }
|
|
5896
5915
|
});
|
|
5897
5916
|
}
|
|
5898
5917
|
/**
|
|
@@ -5908,11 +5927,9 @@ function sheet(o) {
|
|
|
5908
5927
|
});
|
|
5909
5928
|
return group({
|
|
5910
5929
|
label: o.label,
|
|
5930
|
+
icon: o.icon,
|
|
5911
5931
|
fields: flat,
|
|
5912
|
-
view: {
|
|
5913
|
-
...o.view,
|
|
5914
|
-
display: "sheet"
|
|
5915
|
-
}
|
|
5932
|
+
view: { display: "sheet" }
|
|
5916
5933
|
});
|
|
5917
5934
|
}
|
|
5918
5935
|
/**
|
|
@@ -5944,8 +5961,8 @@ function keyed(o) {
|
|
|
5944
5961
|
return {
|
|
5945
5962
|
...(o.container ?? group)({
|
|
5946
5963
|
label: o.label,
|
|
5947
|
-
|
|
5948
|
-
|
|
5964
|
+
icon: o.icon,
|
|
5965
|
+
fields: [o.by, ...o.fields]
|
|
5949
5966
|
}),
|
|
5950
5967
|
key: o.key,
|
|
5951
5968
|
multiple: true,
|
|
@@ -5989,6 +6006,34 @@ function wrapKey(opts, meta) {
|
|
|
5989
6006
|
noEditControl: true
|
|
5990
6007
|
}
|
|
5991
6008
|
};
|
|
6009
|
+
if (opts.emphasis) m = {
|
|
6010
|
+
...m,
|
|
6011
|
+
hints: {
|
|
6012
|
+
...m.hints,
|
|
6013
|
+
emphasis: opts.emphasis
|
|
6014
|
+
}
|
|
6015
|
+
};
|
|
6016
|
+
if (opts.noLabel) m = {
|
|
6017
|
+
...m,
|
|
6018
|
+
hints: {
|
|
6019
|
+
...m.hints,
|
|
6020
|
+
noLabel: true
|
|
6021
|
+
}
|
|
6022
|
+
};
|
|
6023
|
+
if (opts.role) m = {
|
|
6024
|
+
...m,
|
|
6025
|
+
hints: {
|
|
6026
|
+
...m.hints,
|
|
6027
|
+
role: opts.role
|
|
6028
|
+
}
|
|
6029
|
+
};
|
|
6030
|
+
if (opts.pinned) m = {
|
|
6031
|
+
...m,
|
|
6032
|
+
hints: {
|
|
6033
|
+
...m.hints,
|
|
6034
|
+
pinned: true
|
|
6035
|
+
}
|
|
6036
|
+
};
|
|
5992
6037
|
if (opts.default !== void 0) m = {
|
|
5993
6038
|
...m,
|
|
5994
6039
|
default: opts.default
|
|
@@ -6352,8 +6397,8 @@ function relation(raw) {
|
|
|
6352
6397
|
displayKey: o.displayKey ?? "name"
|
|
6353
6398
|
},
|
|
6354
6399
|
relation: {
|
|
6355
|
-
|
|
6356
|
-
|
|
6400
|
+
library: raw.options.library,
|
|
6401
|
+
shelf: raw.options.shelf
|
|
6357
6402
|
},
|
|
6358
6403
|
...multi && { json: true },
|
|
6359
6404
|
zod: optionalize(s, required)
|
|
@@ -6733,15 +6778,44 @@ function period(raw) {
|
|
|
6733
6778
|
zod: optionalize(s, required)
|
|
6734
6779
|
});
|
|
6735
6780
|
}
|
|
6781
|
+
/** Keys a file entry may carry. Everything else is rejected — see fileEntryIssue. */
|
|
6782
|
+
var FILE_KEYS = /* @__PURE__ */ new Set([
|
|
6783
|
+
"name",
|
|
6784
|
+
"mime",
|
|
6785
|
+
"size"
|
|
6786
|
+
]);
|
|
6787
|
+
/** Keys that mean "the author pasted a remote address" — the one mistake worth naming. */
|
|
6788
|
+
var FILE_URL_KEYS = [
|
|
6789
|
+
"url",
|
|
6790
|
+
"src",
|
|
6791
|
+
"href",
|
|
6792
|
+
"link"
|
|
6793
|
+
];
|
|
6794
|
+
/**
|
|
6795
|
+
* A file entry points at a file already uploaded to the server: `{ name }`, where
|
|
6796
|
+
* name is the bare filename returned by POST /api/upload. Anything else — a remote
|
|
6797
|
+
* URL, an extra key, a path — is refused here, so a record can never hold a
|
|
6798
|
+
* reference the server cannot serve. `mime`/`size` are accepted (legacy payloads
|
|
6799
|
+
* and the web uploader send them) but the server overwrites them from disk.
|
|
6800
|
+
* Returns a vmsg code, or null when the entry is well-formed.
|
|
6801
|
+
*/
|
|
6802
|
+
function fileEntryIssue(it) {
|
|
6803
|
+
if (typeof it !== "object" || it === null || Array.isArray(it)) return "file_structure";
|
|
6804
|
+
const rec = it;
|
|
6805
|
+
if (FILE_URL_KEYS.some((k) => k in rec)) return "file_remote_url";
|
|
6806
|
+
const name = rec["name"];
|
|
6807
|
+
if (typeof name !== "string" || name === "") return "file_structure";
|
|
6808
|
+
if (name.includes("://") || name.startsWith("//")) return "file_remote_url";
|
|
6809
|
+
if (/[\\/]/.test(name) || name.includes("..")) return "file_name";
|
|
6810
|
+
for (const k of Object.keys(rec)) if (!FILE_KEYS.has(k)) return "file_unknown_key";
|
|
6811
|
+
if (rec["mime"] !== void 0 && typeof rec["mime"] !== "string") return "file_structure";
|
|
6812
|
+
if (rec["size"] !== void 0 && typeof rec["size"] !== "number") return "file_structure";
|
|
6813
|
+
return null;
|
|
6814
|
+
}
|
|
6736
6815
|
function makeFile(kind, raw) {
|
|
6737
6816
|
const o = normalizeOpts(raw);
|
|
6738
6817
|
const required = o.required ?? false;
|
|
6739
6818
|
const multiple = o.multiple ?? false;
|
|
6740
|
-
const rowSchema = object({
|
|
6741
|
-
name: string$1().min(1),
|
|
6742
|
-
mime: string$1().optional(),
|
|
6743
|
-
size: number$1().optional()
|
|
6744
|
-
});
|
|
6745
6819
|
const s = unknown().superRefine((raw, ctx) => {
|
|
6746
6820
|
if (typeof raw === "string") try {
|
|
6747
6821
|
JSON.parse(raw);
|
|
@@ -6754,12 +6828,15 @@ function makeFile(kind, raw) {
|
|
|
6754
6828
|
}
|
|
6755
6829
|
const parsed = jsonValue(raw);
|
|
6756
6830
|
const items = Array.isArray(parsed) ? parsed : [parsed];
|
|
6757
|
-
for (const it of items)
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6831
|
+
for (const it of items) {
|
|
6832
|
+
const code = fileEntryIssue(it);
|
|
6833
|
+
if (code) {
|
|
6834
|
+
ctx.addIssue({
|
|
6835
|
+
code: ZodIssueCode.custom,
|
|
6836
|
+
message: vmsg(code)
|
|
6837
|
+
});
|
|
6838
|
+
return;
|
|
6839
|
+
}
|
|
6763
6840
|
}
|
|
6764
6841
|
});
|
|
6765
6842
|
return wrapKey(o, {
|
|
@@ -7003,7 +7080,7 @@ function toClient(field) {
|
|
|
7003
7080
|
var src_default = definePlugin({
|
|
7004
7081
|
id: "orchestrator",
|
|
7005
7082
|
version: "1.0.0",
|
|
7006
|
-
dependsOn: ["agent"],
|
|
7083
|
+
dependsOn: ["claude-agent"],
|
|
7007
7084
|
settings: defineSettings({
|
|
7008
7085
|
label: "orchestrator.settings.label",
|
|
7009
7086
|
fields: [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coffer-org/plugin-orchestrator",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=24"
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"postpack": "node ../../scripts/swap-exports.mjs src"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@coffer-org/sdk": "^
|
|
29
|
-
"@coffer-org/server": "^
|
|
30
|
-
"@coffer-org/plugin-agent": "^
|
|
28
|
+
"@coffer-org/sdk": "^2.0.0",
|
|
29
|
+
"@coffer-org/server": "^2.0.1",
|
|
30
|
+
"@coffer-org/plugin-claude-agent": "^2.0.0"
|
|
31
31
|
},
|
|
32
32
|
"coffer": {
|
|
33
33
|
"schema": "dist/schema.js"
|