@decibelsystems/tools 2.2.0-beta.0 → 3.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/CHANGELOG.md +160 -0
- package/dist/agentPresence.d.ts +80 -0
- package/dist/agentPresence.d.ts.map +1 -1
- package/dist/agentPresence.js +177 -0
- package/dist/agentPresence.js.map +1 -1
- package/dist/agentic/index.d.ts +18 -8
- package/dist/agentic/index.d.ts.map +1 -1
- package/dist/agentic/index.js +18 -144
- package/dist/agentic/index.js.map +1 -1
- package/dist/agentic/types.d.ts +106 -0
- package/dist/agentic/types.d.ts.map +1 -1
- package/dist/agentic/types.js +77 -1
- package/dist/agentic/types.js.map +1 -1
- package/dist/architectAdrs.d.ts +14 -2
- package/dist/architectAdrs.d.ts.map +1 -1
- package/dist/architectAdrs.js +9 -3
- package/dist/architectAdrs.js.map +1 -1
- package/dist/client/transports.d.ts.map +1 -1
- package/dist/client/transports.js +13 -3
- package/dist/client/transports.js.map +1 -1
- package/dist/daemon.d.ts +19 -0
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +181 -38
- package/dist/daemon.js.map +1 -1
- package/dist/daemonConfig.d.ts +24 -0
- package/dist/daemonConfig.d.ts.map +1 -1
- package/dist/daemonConfig.js +46 -12
- package/dist/daemonConfig.js.map +1 -1
- package/dist/decibelPaths.d.ts.map +1 -1
- package/dist/decibelPaths.js +39 -6
- package/dist/decibelPaths.js.map +1 -1
- package/dist/domain/issue.d.ts +77 -0
- package/dist/domain/issue.d.ts.map +1 -0
- package/dist/domain/issue.js +134 -0
- package/dist/domain/issue.js.map +1 -0
- package/dist/domain/issueCodec.d.ts +39 -0
- package/dist/domain/issueCodec.d.ts.map +1 -0
- package/dist/domain/issueCodec.js +298 -0
- package/dist/domain/issueCodec.js.map +1 -0
- package/dist/domain/issueRepository.d.ts +91 -0
- package/dist/domain/issueRepository.d.ts.map +1 -0
- package/dist/domain/issueRepository.js +257 -0
- package/dist/domain/issueRepository.js.map +1 -0
- package/dist/facades/definitions.d.ts +0 -1
- package/dist/facades/definitions.d.ts.map +1 -1
- package/dist/facades/definitions.js +94 -113
- package/dist/facades/definitions.js.map +1 -1
- package/dist/facades/index.d.ts +2 -1
- package/dist/facades/index.d.ts.map +1 -1
- package/dist/facades/index.js +1 -1
- package/dist/facades/index.js.map +1 -1
- package/dist/facades/types.d.ts +17 -0
- package/dist/facades/types.d.ts.map +1 -1
- package/dist/httpArgs.d.ts +11 -0
- package/dist/httpArgs.d.ts.map +1 -0
- package/dist/httpArgs.js +39 -0
- package/dist/httpArgs.js.map +1 -0
- package/dist/httpServer.d.ts +1 -12
- package/dist/httpServer.d.ts.map +1 -1
- package/dist/httpServer.js +97 -96
- package/dist/httpServer.js.map +1 -1
- package/dist/kernel.d.ts +46 -1
- package/dist/kernel.d.ts.map +1 -1
- package/dist/kernel.js +311 -26
- package/dist/kernel.js.map +1 -1
- package/dist/lib/agent-services/assumptions.d.ts.map +1 -1
- package/dist/lib/agent-services/assumptions.js +8 -2
- package/dist/lib/agent-services/assumptions.js.map +1 -1
- package/dist/lib/atomicWrite.d.ts +26 -0
- package/dist/lib/atomicWrite.d.ts.map +1 -0
- package/dist/lib/atomicWrite.js +73 -0
- package/dist/lib/atomicWrite.js.map +1 -0
- package/dist/lib/envelope.d.ts +31 -0
- package/dist/lib/envelope.d.ts.map +1 -0
- package/dist/lib/envelope.js +80 -0
- package/dist/lib/envelope.js.map +1 -0
- package/dist/lib/fileLock.d.ts +38 -0
- package/dist/lib/fileLock.d.ts.map +1 -0
- package/dist/lib/fileLock.js +124 -0
- package/dist/lib/fileLock.js.map +1 -0
- package/dist/lib/recordIdAllocator.d.ts +86 -0
- package/dist/lib/recordIdAllocator.d.ts.map +1 -0
- package/dist/lib/recordIdAllocator.js +161 -0
- package/dist/lib/recordIdAllocator.js.map +1 -0
- package/dist/projectRegistry.d.ts.map +1 -1
- package/dist/projectRegistry.js +11 -0
- package/dist/projectRegistry.js.map +1 -1
- package/dist/runtime/circuitBreaker.d.ts +95 -0
- package/dist/runtime/circuitBreaker.d.ts.map +1 -0
- package/dist/runtime/circuitBreaker.js +178 -0
- package/dist/runtime/circuitBreaker.js.map +1 -0
- package/dist/runtime/ensureRuntime.d.ts +103 -0
- package/dist/runtime/ensureRuntime.d.ts.map +1 -0
- package/dist/runtime/ensureRuntime.js +281 -0
- package/dist/runtime/ensureRuntime.js.map +1 -0
- package/dist/runtime/extensions.d.ts +57 -0
- package/dist/runtime/extensions.d.ts.map +1 -0
- package/dist/runtime/extensions.js +216 -0
- package/dist/runtime/extensions.js.map +1 -0
- package/dist/runtime/localHttp.d.ts +24 -0
- package/dist/runtime/localHttp.d.ts.map +1 -0
- package/dist/runtime/localHttp.js +84 -0
- package/dist/runtime/localHttp.js.map +1 -0
- package/dist/runtime/projectResolution.d.ts +29 -0
- package/dist/runtime/projectResolution.d.ts.map +1 -0
- package/dist/runtime/projectResolution.js +67 -0
- package/dist/runtime/projectResolution.js.map +1 -0
- package/dist/runtime/protocol.d.ts +62 -0
- package/dist/runtime/protocol.d.ts.map +1 -0
- package/dist/runtime/protocol.js +74 -0
- package/dist/runtime/protocol.js.map +1 -0
- package/dist/sentinelIssues.d.ts +26 -2
- package/dist/sentinelIssues.d.ts.map +1 -1
- package/dist/sentinelIssues.js +125 -64
- package/dist/sentinelIssues.js.map +1 -1
- package/dist/server.js +59 -12
- package/dist/server.js.map +1 -1
- package/dist/tools/agentic/index.d.ts.map +1 -1
- package/dist/tools/agentic/index.js +28 -2
- package/dist/tools/agentic/index.js.map +1 -1
- package/dist/tools/architect/index.d.ts.map +1 -1
- package/dist/tools/architect/index.js +7 -2
- package/dist/tools/architect/index.js.map +1 -1
- package/dist/tools/context.d.ts +10 -5
- package/dist/tools/context.d.ts.map +1 -1
- package/dist/tools/context.js +45 -18
- package/dist/tools/context.js.map +1 -1
- package/dist/tools/coordinator/coordinator.d.ts.map +1 -1
- package/dist/tools/coordinator/coordinator.js +48 -19
- package/dist/tools/coordinator/coordinator.js.map +1 -1
- package/dist/tools/crit.d.ts +2 -1
- package/dist/tools/crit.d.ts.map +1 -1
- package/dist/tools/crit.js +19 -4
- package/dist/tools/crit.js.map +1 -1
- package/dist/tools/designer/index.d.ts.map +1 -1
- package/dist/tools/designer/index.js +4 -3
- package/dist/tools/designer/index.js.map +1 -1
- package/dist/tools/designer/lateral-tools.d.ts.map +1 -1
- package/dist/tools/designer/lateral-tools.js +4 -2
- package/dist/tools/designer/lateral-tools.js.map +1 -1
- package/dist/tools/designer.d.ts +2 -1
- package/dist/tools/designer.d.ts.map +1 -1
- package/dist/tools/designer.js +24 -12
- package/dist/tools/designer.js.map +1 -1
- package/dist/tools/dojo.d.ts +3 -2
- package/dist/tools/dojo.d.ts.map +1 -1
- package/dist/tools/dojo.js +64 -22
- package/dist/tools/dojo.js.map +1 -1
- package/dist/tools/friction.d.ts.map +1 -1
- package/dist/tools/friction.js +16 -6
- package/dist/tools/friction.js.map +1 -1
- package/dist/tools/guardian.d.ts.map +1 -1
- package/dist/tools/guardian.js +6 -2
- package/dist/tools/guardian.js.map +1 -1
- package/dist/tools/hygiene/oracle-hygiene.d.ts.map +1 -1
- package/dist/tools/hygiene/oracle-hygiene.js +8 -2
- package/dist/tools/hygiene/oracle-hygiene.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +27 -18
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/learnings.d.ts +2 -1
- package/dist/tools/learnings.d.ts.map +1 -1
- package/dist/tools/learnings.js +31 -15
- package/dist/tools/learnings.js.map +1 -1
- package/dist/tools/oracle.d.ts.map +1 -1
- package/dist/tools/oracle.js +19 -6
- package/dist/tools/oracle.js.map +1 -1
- package/dist/tools/policy.d.ts +2 -1
- package/dist/tools/policy.d.ts.map +1 -1
- package/dist/tools/policy.js +28 -9
- package/dist/tools/policy.js.map +1 -1
- package/dist/tools/postoffice/index.d.ts +10 -0
- package/dist/tools/postoffice/index.d.ts.map +1 -0
- package/dist/tools/postoffice/index.js +218 -0
- package/dist/tools/postoffice/index.js.map +1 -0
- package/dist/tools/postoffice.d.ts +78 -0
- package/dist/tools/postoffice.d.ts.map +1 -0
- package/dist/tools/postoffice.js +199 -0
- package/dist/tools/postoffice.js.map +1 -0
- package/dist/tools/provenance.d.ts +7 -0
- package/dist/tools/provenance.d.ts.map +1 -1
- package/dist/tools/provenance.js +42 -16
- package/dist/tools/provenance.js.map +1 -1
- package/dist/tools/sentinel/index.d.ts +1 -0
- package/dist/tools/sentinel/index.d.ts.map +1 -1
- package/dist/tools/sentinel/index.js +88 -4
- package/dist/tools/sentinel/index.js.map +1 -1
- package/dist/tools/sentinel.d.ts +102 -1
- package/dist/tools/sentinel.d.ts.map +1 -1
- package/dist/tools/sentinel.js +544 -328
- package/dist/tools/sentinel.js.map +1 -1
- package/dist/tools/shared/index.d.ts +2 -1
- package/dist/tools/shared/index.d.ts.map +1 -1
- package/dist/tools/shared/index.js +2 -1
- package/dist/tools/shared/index.js.map +1 -1
- package/dist/tools/shared/response.d.ts +24 -0
- package/dist/tools/shared/response.d.ts.map +1 -1
- package/dist/tools/shared/response.js +61 -7
- package/dist/tools/shared/response.js.map +1 -1
- package/dist/tools/shared/storeRead.d.ts +153 -0
- package/dist/tools/shared/storeRead.d.ts.map +1 -0
- package/dist/tools/shared/storeRead.js +242 -0
- package/dist/tools/shared/storeRead.js.map +1 -0
- package/dist/tools/testSpec.d.ts +3 -2
- package/dist/tools/testSpec.d.ts.map +1 -1
- package/dist/tools/testSpec.js +51 -14
- package/dist/tools/testSpec.js.map +1 -1
- package/dist/tools/vector.d.ts +33 -1
- package/dist/tools/vector.d.ts.map +1 -1
- package/dist/tools/vector.js +31 -5
- package/dist/tools/vector.js.map +1 -1
- package/dist/tools/zoom/index.d.ts +15 -0
- package/dist/tools/zoom/index.d.ts.map +1 -0
- package/dist/tools/zoom/index.js +174 -0
- package/dist/tools/zoom/index.js.map +1 -0
- package/dist/tools/zoom.d.ts +234 -0
- package/dist/tools/zoom.d.ts.map +1 -0
- package/dist/tools/zoom.js +627 -0
- package/dist/tools/zoom.js.map +1 -0
- package/dist/transports/bridge.d.ts +1 -1
- package/dist/transports/bridge.d.ts.map +1 -1
- package/dist/transports/bridge.js +2 -0
- package/dist/transports/bridge.js.map +1 -1
- package/dist/transports/http.d.ts +1 -1
- package/dist/transports/http.d.ts.map +1 -1
- package/dist/transports/http.js +3 -1
- package/dist/transports/http.js.map +1 -1
- package/dist/transports/index.d.ts +1 -0
- package/dist/transports/index.d.ts.map +1 -1
- package/dist/transports/index.js +1 -0
- package/dist/transports/index.js.map +1 -1
- package/dist/transports/mcp.d.ts +1 -1
- package/dist/transports/mcp.d.ts.map +1 -1
- package/dist/transports/mcp.js +7 -3
- package/dist/transports/mcp.js.map +1 -1
- package/dist/transports/stdio.d.ts +1 -1
- package/dist/transports/stdio.d.ts.map +1 -1
- package/dist/transports/stdio.js +2 -0
- package/dist/transports/stdio.js.map +1 -1
- package/dist/transports/thinStdio.d.ts +22 -0
- package/dist/transports/thinStdio.d.ts.map +1 -0
- package/dist/transports/thinStdio.js +218 -0
- package/dist/transports/thinStdio.js.map +1 -0
- package/dist/transports/types.d.ts +8 -1
- package/dist/transports/types.d.ts.map +1 -1
- package/dist/types/agent-services.d.ts +7 -0
- package/dist/types/agent-services.d.ts.map +1 -1
- package/package.json +9 -4
- package/templates/com.decibel.daemon.plist +6 -1
- package/dist/tools/deck.d.ts +0 -11
- package/dist/tools/deck.d.ts.map +0 -1
- package/dist/tools/deck.js +0 -1656
- package/dist/tools/deck.js.map +0 -1
- package/dist/tools/mother.d.ts +0 -11
- package/dist/tools/mother.d.ts.map +0 -1
- package/dist/tools/mother.js +0 -503
- package/dist/tools/mother.js.map +0 -1
- package/dist/tools/registry.d.ts +0 -3
- package/dist/tools/registry.d.ts.map +0 -1
- package/dist/tools/registry.js +0 -189
- package/dist/tools/registry.js.map +0 -1
- package/dist/tools/senken.d.ts +0 -11
- package/dist/tools/senken.d.ts.map +0 -1
- package/dist/tools/senken.js +0 -482
- package/dist/tools/senken.js.map +0 -1
- package/dist/tools/terminal.d.ts +0 -17
- package/dist/tools/terminal.d.ts.map +0 -1
- package/dist/tools/terminal.js +0 -968
- package/dist/tools/terminal.js.map +0 -1
- package/dist/tools/toolsIndex.d.ts +0 -5
- package/dist/tools/toolsIndex.d.ts.map +0 -1
- package/dist/tools/toolsIndex.js +0 -37
- package/dist/tools/toolsIndex.js.map +0 -1
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Post Office Tools — EPIC-0037
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// Seven verbs, one per tool. The surface is deliberately exactly the far side's
|
|
5
|
+
// surface: an eighth verb is a contract change across two repos, so there is no
|
|
6
|
+
// convenience action here that composes several.
|
|
7
|
+
// ============================================================================
|
|
8
|
+
import { toolSuccess, toolError, requireFields } from '../shared/index.js';
|
|
9
|
+
import { agentsList, threadsOpen, messagesSend, messagesRead, messagesAck, handoffRequest, handoffRespond, isPostOfficeError, } from '../postoffice.js';
|
|
10
|
+
/**
|
|
11
|
+
* Post office failures carry a code and usually a hint that names the fix.
|
|
12
|
+
* Flattening them into a bare message would discard the actionable half — an
|
|
13
|
+
* unconfigured credential and a revoked one need different responses.
|
|
14
|
+
*/
|
|
15
|
+
function settle(result) {
|
|
16
|
+
if (isPostOfficeError(result)) {
|
|
17
|
+
return toolError(JSON.stringify({ error: result.error, code: result.code, hint: result.hint }));
|
|
18
|
+
}
|
|
19
|
+
return toolSuccess(result);
|
|
20
|
+
}
|
|
21
|
+
export const postOfficeAgentsListTool = {
|
|
22
|
+
definition: {
|
|
23
|
+
name: 'postoffice_agents_list',
|
|
24
|
+
description: 'List agents reachable through AgentHQ, with live presence. A view over presence, not a second roster.',
|
|
25
|
+
annotations: { title: 'List Agents', readOnlyHint: true, destructiveHint: false, idempotentHint: true },
|
|
26
|
+
inputSchema: { type: 'object', properties: {} },
|
|
27
|
+
},
|
|
28
|
+
handler: async () => {
|
|
29
|
+
try {
|
|
30
|
+
return settle(await agentsList());
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
return toolError(err instanceof Error ? err.message : String(err));
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
export const postOfficeThreadsOpenTool = {
|
|
38
|
+
definition: {
|
|
39
|
+
name: 'postoffice_threads_open',
|
|
40
|
+
description: 'Open a conversation thread. A thread is the unit a handoff happens inside — open one before sending.',
|
|
41
|
+
annotations: { title: 'Open Thread', readOnlyHint: false, destructiveHint: false, idempotentHint: false },
|
|
42
|
+
inputSchema: {
|
|
43
|
+
type: 'object',
|
|
44
|
+
properties: {
|
|
45
|
+
subject: { type: 'string', description: 'What the thread is about. Required.' },
|
|
46
|
+
project: { type: 'string', description: 'Optional HQ project UUID (not a Decibel project slug — hq.agent_threads.project_id is a uuid). Omit unless you hold the uuid.' },
|
|
47
|
+
intent: { type: 'string', description: 'Optional free-text intent for the thread as a whole.' },
|
|
48
|
+
},
|
|
49
|
+
required: ['subject'],
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
handler: async (args) => {
|
|
53
|
+
try {
|
|
54
|
+
requireFields(args, 'subject');
|
|
55
|
+
return settle(await threadsOpen(args));
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
return toolError(err instanceof Error ? err.message : String(err));
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
export const postOfficeMessagesSendTool = {
|
|
63
|
+
definition: {
|
|
64
|
+
name: 'postoffice_messages_send',
|
|
65
|
+
description: 'Send a message to another agent inside a thread. The recipient is addressed by agent name or id; the sender is taken from the credential and cannot be spoofed.',
|
|
66
|
+
annotations: { title: 'Send Message', readOnlyHint: false, destructiveHint: false, idempotentHint: false },
|
|
67
|
+
inputSchema: {
|
|
68
|
+
type: 'object',
|
|
69
|
+
properties: {
|
|
70
|
+
to: { type: 'string', description: 'Recipient agent name or uuid, in your org.' },
|
|
71
|
+
thread: { type: 'string', description: 'Thread id from postoffice_threads_open.' },
|
|
72
|
+
summary: { type: 'string', description: 'The message. Max 2048 characters.' },
|
|
73
|
+
intent: {
|
|
74
|
+
type: 'string',
|
|
75
|
+
enum: ['inform', 'request', 'respond'],
|
|
76
|
+
description: 'Why you are writing. Defaults to inform. Handoff intents are set by the handoff tools.',
|
|
77
|
+
},
|
|
78
|
+
context_refs: {
|
|
79
|
+
type: 'array',
|
|
80
|
+
items: { type: 'string' },
|
|
81
|
+
description: 'Up to 32 references (issue ids, file paths, URLs) the recipient will need.',
|
|
82
|
+
},
|
|
83
|
+
request: { type: 'string', description: 'What you are asking for, when intent is request.' },
|
|
84
|
+
expected_output: { type: 'string', description: 'What a good answer looks like. Max 1024 characters.' },
|
|
85
|
+
},
|
|
86
|
+
required: ['to', 'thread', 'summary'],
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
handler: async (args) => {
|
|
90
|
+
try {
|
|
91
|
+
requireFields(args, 'to', 'thread', 'summary');
|
|
92
|
+
return settle(await messagesSend(args));
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
return toolError(err instanceof Error ? err.message : String(err));
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
export const postOfficeMessagesReadTool = {
|
|
100
|
+
definition: {
|
|
101
|
+
name: 'postoffice_messages_read',
|
|
102
|
+
description: 'Read your mail. Reading does NOT acknowledge — ack separately with postoffice_messages_ack once you have acted. Do not poll with status="sent": reading marks sent->read, so that filter cannot return a message twice and a reader that dies before acting loses it silently. Leave status unset to see everything still addressed to you.',
|
|
103
|
+
annotations: { title: 'Read Messages', readOnlyHint: false, destructiveHint: false, idempotentHint: false },
|
|
104
|
+
inputSchema: {
|
|
105
|
+
type: 'object',
|
|
106
|
+
properties: {
|
|
107
|
+
thread: { type: 'string', description: 'Optional: restrict to one thread.' },
|
|
108
|
+
status: {
|
|
109
|
+
type: 'string',
|
|
110
|
+
enum: ['sent', 'read', 'acked', 'failed'],
|
|
111
|
+
description: 'Optional exact-status filter. Omit when polling — see the tool description.',
|
|
112
|
+
},
|
|
113
|
+
limit: { type: 'number', description: 'Max messages to return. Default 25, capped at 100.' },
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
handler: async (args) => {
|
|
118
|
+
try {
|
|
119
|
+
return settle(await messagesRead((args ?? {})));
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
return toolError(err instanceof Error ? err.message : String(err));
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
export const postOfficeMessagesAckTool = {
|
|
127
|
+
definition: {
|
|
128
|
+
name: 'postoffice_messages_ack',
|
|
129
|
+
description: 'Acknowledge a message: "I have this and I am acting on it." Separate from reading on purpose. Acking twice is not an error and does not change status, but it currently REWRITES acked_at to the later time — so a retry moves the recorded acknowledgement time. Only the recipient can ack.',
|
|
130
|
+
// idempotentHint is FALSE deliberately, and it is not a mistake that the
|
|
131
|
+
// description says acking twice is safe. Status is idempotent; acked_at is
|
|
132
|
+
// not — a double ack measured 0.959s of drift against the live service on
|
|
133
|
+
// 2026-08-31, and the drift always moves the timestamp LATER, which flatters
|
|
134
|
+
// any ack-latency measure. A retry-on-timeout is exactly when a client acks
|
|
135
|
+
// twice and exactly when the first ack probably landed, so the error
|
|
136
|
+
// correlates with slow calls and hides them.
|
|
137
|
+
//
|
|
138
|
+
// Claiming idempotent here would tell a client that retrying is free. It is
|
|
139
|
+
// free for delivery and not free for the record. HQ owns the fix
|
|
140
|
+
// (coalesce(acked_at, now()) server-side); when it lands this flips back to
|
|
141
|
+
// true and this comment explains why it ever moved.
|
|
142
|
+
annotations: { title: 'Ack Message', readOnlyHint: false, destructiveHint: false, idempotentHint: false },
|
|
143
|
+
inputSchema: {
|
|
144
|
+
type: 'object',
|
|
145
|
+
properties: { message: { type: 'string', description: 'Message id to acknowledge.' } },
|
|
146
|
+
required: ['message'],
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
handler: async (args) => {
|
|
150
|
+
try {
|
|
151
|
+
requireFields(args, 'message');
|
|
152
|
+
return settle(await messagesAck(args));
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
return toolError(err instanceof Error ? err.message : String(err));
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
export const postOfficeHandoffRequestTool = {
|
|
160
|
+
definition: {
|
|
161
|
+
name: 'postoffice_handoff_request',
|
|
162
|
+
description: 'Ask another agent to take over a thread. Writes a handoff_request message so the handoff is legible in the thread it happened in, rather than in a side table.',
|
|
163
|
+
annotations: { title: 'Request Handoff', readOnlyHint: false, destructiveHint: false, idempotentHint: false },
|
|
164
|
+
inputSchema: {
|
|
165
|
+
type: 'object',
|
|
166
|
+
properties: {
|
|
167
|
+
thread: { type: 'string', description: 'Thread to hand over.' },
|
|
168
|
+
to: { type: 'string', description: 'Agent to hand it to, by name or uuid.' },
|
|
169
|
+
summary: { type: 'string', description: 'What you are handing over and what state it is in.' },
|
|
170
|
+
},
|
|
171
|
+
required: ['thread'],
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
handler: async (args) => {
|
|
175
|
+
try {
|
|
176
|
+
requireFields(args, 'thread');
|
|
177
|
+
return settle(await handoffRequest(args));
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
return toolError(err instanceof Error ? err.message : String(err));
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
export const postOfficeHandoffRespondTool = {
|
|
185
|
+
definition: {
|
|
186
|
+
name: 'postoffice_handoff_respond',
|
|
187
|
+
description: 'Accept or decline a handoff you were offered. Writes a handoff_respond message into the same thread.',
|
|
188
|
+
annotations: { title: 'Respond to Handoff', readOnlyHint: false, destructiveHint: false, idempotentHint: false },
|
|
189
|
+
inputSchema: {
|
|
190
|
+
type: 'object',
|
|
191
|
+
properties: {
|
|
192
|
+
thread: { type: 'string', description: 'Thread the handoff was offered in.' },
|
|
193
|
+
accept: { type: 'boolean', description: 'true to take it, false to decline.' },
|
|
194
|
+
summary: { type: 'string', description: 'Optional note explaining the decision.' },
|
|
195
|
+
},
|
|
196
|
+
required: ['thread', 'accept'],
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
handler: async (args) => {
|
|
200
|
+
try {
|
|
201
|
+
requireFields(args, 'thread', 'accept');
|
|
202
|
+
return settle(await handoffRespond(args));
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
return toolError(err instanceof Error ? err.message : String(err));
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
export const postOfficeTools = [
|
|
210
|
+
postOfficeAgentsListTool,
|
|
211
|
+
postOfficeThreadsOpenTool,
|
|
212
|
+
postOfficeMessagesSendTool,
|
|
213
|
+
postOfficeMessagesReadTool,
|
|
214
|
+
postOfficeMessagesAckTool,
|
|
215
|
+
postOfficeHandoffRequestTool,
|
|
216
|
+
postOfficeHandoffRespondTool,
|
|
217
|
+
];
|
|
218
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/postoffice/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/** The seven verbs the far side implements. An eighth is a two-repo change. */
|
|
2
|
+
export type PostOfficeVerb = 'agents.list' | 'threads.open' | 'messages.send' | 'messages.read' | 'messages.ack' | 'handoff.request' | 'handoff.respond';
|
|
3
|
+
export interface PostOfficeError {
|
|
4
|
+
error: string;
|
|
5
|
+
code: 'HQ_NOT_CONFIGURED' | 'HQ_UNAUTHORIZED' | 'HQ_FORBIDDEN' | 'HQ_NOT_FOUND' | 'HQ_REJECTED' | 'HQ_UNAVAILABLE';
|
|
6
|
+
hint?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function isPostOfficeError(v: unknown): v is PostOfficeError;
|
|
9
|
+
/**
|
|
10
|
+
* One request to the post office.
|
|
11
|
+
*
|
|
12
|
+
* Every failure is mapped to something a caller can act on. The far side is
|
|
13
|
+
* deliberate about its status codes — 403 names the scope it wanted, 404
|
|
14
|
+
* distinguishes an unknown recipient from an unknown thread — and flattening
|
|
15
|
+
* those into "request failed" would discard the part that tells you what to fix.
|
|
16
|
+
*/
|
|
17
|
+
export declare function postOfficeCall(verb: PostOfficeVerb, payload?: Record<string, unknown>): Promise<Record<string, unknown> | PostOfficeError>;
|
|
18
|
+
export declare function agentsList(): Promise<Record<string, unknown> | PostOfficeError>;
|
|
19
|
+
export interface ThreadsOpenInput {
|
|
20
|
+
subject: string;
|
|
21
|
+
/**
|
|
22
|
+
* HQ project UUID, NOT a Decibel project slug. hq.agent_threads.project_id is
|
|
23
|
+
* a uuid referencing hq.projects, so passing 'decibel-tools-mcp' is rejected
|
|
24
|
+
* by Postgres rather than resolved. There is no lookup verb in the seven, so
|
|
25
|
+
* a caller that does not already hold the uuid should omit this.
|
|
26
|
+
*/
|
|
27
|
+
project?: string;
|
|
28
|
+
intent?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare function threadsOpen(input: ThreadsOpenInput): Promise<Record<string, unknown> | PostOfficeError>;
|
|
31
|
+
export interface MessagesSendInput {
|
|
32
|
+
to: string;
|
|
33
|
+
thread: string;
|
|
34
|
+
summary: string;
|
|
35
|
+
intent?: 'inform' | 'request' | 'respond';
|
|
36
|
+
context_refs?: string[];
|
|
37
|
+
request?: string;
|
|
38
|
+
expected_output?: string;
|
|
39
|
+
}
|
|
40
|
+
export declare function messagesSend(input: MessagesSendInput): Promise<Record<string, unknown> | PostOfficeError>;
|
|
41
|
+
export interface MessagesReadInput {
|
|
42
|
+
thread?: string;
|
|
43
|
+
status?: string;
|
|
44
|
+
limit?: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Read this agent's mail.
|
|
48
|
+
*
|
|
49
|
+
* `status` is deliberately NOT defaulted, and polling must not set it to
|
|
50
|
+
* 'sent'. The far side marks sent -> read as a side effect of reading, so a
|
|
51
|
+
* mailbox query filtered to status='sent' never returns a message twice: a
|
|
52
|
+
* reader that fetches and then dies before acting has silently consumed it,
|
|
53
|
+
* and no restart recovers it. Unfiltered, the same message comes back as
|
|
54
|
+
* 'read' and can still be acted on.
|
|
55
|
+
*
|
|
56
|
+
* That is the whole reason read and ack are separate verbs — at-least-once
|
|
57
|
+
* beats at-most-once here, because a duplicated message costs a minute and a
|
|
58
|
+
* dropped handoff stalls work invisibly.
|
|
59
|
+
*/
|
|
60
|
+
export declare function messagesRead(input?: MessagesReadInput): Promise<Record<string, unknown> | PostOfficeError>;
|
|
61
|
+
export interface MessagesAckInput {
|
|
62
|
+
message: string;
|
|
63
|
+
}
|
|
64
|
+
/** Idempotent by construction on the far side: acking twice is not an error. */
|
|
65
|
+
export declare function messagesAck(input: MessagesAckInput): Promise<Record<string, unknown> | PostOfficeError>;
|
|
66
|
+
export interface HandoffRequestInput {
|
|
67
|
+
thread: string;
|
|
68
|
+
to?: string;
|
|
69
|
+
summary?: string;
|
|
70
|
+
}
|
|
71
|
+
export declare function handoffRequest(input: HandoffRequestInput): Promise<Record<string, unknown> | PostOfficeError>;
|
|
72
|
+
export interface HandoffRespondInput {
|
|
73
|
+
thread: string;
|
|
74
|
+
accept: boolean;
|
|
75
|
+
summary?: string;
|
|
76
|
+
}
|
|
77
|
+
export declare function handoffRespond(input: HandoffRespondInput): Promise<Record<string, unknown> | PostOfficeError>;
|
|
78
|
+
//# sourceMappingURL=postoffice.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postoffice.d.ts","sourceRoot":"","sources":["../../src/tools/postoffice.ts"],"names":[],"mappings":"AAiCA,+EAA+E;AAC/E,MAAM,MAAM,cAAc,GACtB,aAAa,GACb,cAAc,GACd,eAAe,GACf,eAAe,GACf,cAAc,GACd,iBAAiB,GACjB,iBAAiB,CAAC;AAEtB,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EACA,mBAAmB,GACnB,iBAAiB,GACjB,cAAc,GACd,cAAc,GACd,aAAa,GACb,gBAAgB,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,eAAe,CAElE;AA+BD;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,cAAc,EACpB,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACpC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,CAAC,CAqFpD;AAMD,wBAAgB,UAAU,uDAEzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,sDAMlD;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;IAC1C,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AACD,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,sDAEpD;AAED,MAAM,WAAW,iBAAiB;IAAG,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CAAE;AACxF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,KAAK,GAAE,iBAAsB,sDAMzD;AAED,MAAM,WAAW,gBAAgB;IAAG,OAAO,EAAE,MAAM,CAAC;CAAE;AACtD,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,sDAElD;AAED,MAAM,WAAW,mBAAmB;IAAG,MAAM,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAAE;AACvF,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,sDAExD;AAED,MAAM,WAAW,mBAAmB;IAAG,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAAE;AAC3F,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,sDAExD"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Post Office — the client half of EPIC-0037
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// AgentHQ runs the post office: hq.agent_threads / hq.agent_messages behind an
|
|
5
|
+
// edge function that speaks seven verbs over a bearer credential. ChatGPT could
|
|
6
|
+
// already authenticate and write into a thread; Claude Code could not read or
|
|
7
|
+
// ack, which is the only thing that stood between here and a round trip.
|
|
8
|
+
//
|
|
9
|
+
// This module is a transport, not a second model. It does not cache messages,
|
|
10
|
+
// does not maintain its own inbox, and does not decide delivery — the runtime
|
|
11
|
+
// on the other side owns all of that. Everything here maps one facade action to
|
|
12
|
+
// one verb and surfaces what came back.
|
|
13
|
+
//
|
|
14
|
+
// THE CREDENTIAL IS NEVER LOGGED. It is read from the environment or
|
|
15
|
+
// ~/.decibel/config.yaml and used only as an Authorization header. It is not a
|
|
16
|
+
// tool argument, so it never reaches ~/.decibel/logs/dispatch.jsonl, which is
|
|
17
|
+
// written to disk in plaintext. Nothing here may put it in an error message
|
|
18
|
+
// either: an access token lasts an hour and a refresh token thirty days, so a
|
|
19
|
+
// leak into a rotated log file is not a momentary exposure.
|
|
20
|
+
// ============================================================================
|
|
21
|
+
import { log } from '../config.js';
|
|
22
|
+
import { loadConfig } from '../daemonConfig.js';
|
|
23
|
+
/**
|
|
24
|
+
* Default origin. NOT hq.decibelsystems.com — that host has no DNS at all
|
|
25
|
+
* (verified 2026-08-30, unresolvable). Pointing at it fails closed with a
|
|
26
|
+
* DNS error rather than anything a caller can act on.
|
|
27
|
+
*/
|
|
28
|
+
const DEFAULT_HQ_URL = 'https://home.theagenthq.app';
|
|
29
|
+
const POST_OFFICE_PATH = '/agents/mcp';
|
|
30
|
+
const REQUEST_TIMEOUT_MS = 15_000;
|
|
31
|
+
export function isPostOfficeError(v) {
|
|
32
|
+
return typeof v === 'object' && v !== null && 'code' in v && 'error' in v;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Resolve the endpoint and credential.
|
|
36
|
+
*
|
|
37
|
+
* Env wins over config so a session can point at a staging HQ without editing
|
|
38
|
+
* a file that other processes read. Returns an error rather than throwing,
|
|
39
|
+
* because "you have not set this up yet" is a normal state for most projects
|
|
40
|
+
* and should read as instructions, not as a stack trace.
|
|
41
|
+
*/
|
|
42
|
+
function resolveCredential() {
|
|
43
|
+
const cfg = loadConfig();
|
|
44
|
+
const url = (process.env.DECIBEL_HQ_URL || cfg.hq?.url || DEFAULT_HQ_URL).replace(/\/+$/, '');
|
|
45
|
+
const token = process.env.DECIBEL_HQ_TOKEN || cfg.hq?.token;
|
|
46
|
+
if (!token) {
|
|
47
|
+
return {
|
|
48
|
+
error: 'No AgentHQ credential is configured, so this agent cannot reach the post office.',
|
|
49
|
+
code: 'HQ_NOT_CONFIGURED',
|
|
50
|
+
hint: 'A credential is issued once and never recoverable. An org admin runs ' +
|
|
51
|
+
"hq.issue_agent_token(p_org, p_agent_name, ...) and it returns the raw token exactly once. " +
|
|
52
|
+
'Then set DECIBEL_HQ_TOKEN, or add hq.token to ~/.decibel/config.yaml. ' +
|
|
53
|
+
`Endpoint currently resolves to ${url}${POST_OFFICE_PATH}.`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return { url, token };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* One request to the post office.
|
|
60
|
+
*
|
|
61
|
+
* Every failure is mapped to something a caller can act on. The far side is
|
|
62
|
+
* deliberate about its status codes — 403 names the scope it wanted, 404
|
|
63
|
+
* distinguishes an unknown recipient from an unknown thread — and flattening
|
|
64
|
+
* those into "request failed" would discard the part that tells you what to fix.
|
|
65
|
+
*/
|
|
66
|
+
export async function postOfficeCall(verb, payload = {}) {
|
|
67
|
+
const cred = resolveCredential();
|
|
68
|
+
if (isPostOfficeError(cred))
|
|
69
|
+
return cred;
|
|
70
|
+
const endpoint = `${cred.url}${POST_OFFICE_PATH}`;
|
|
71
|
+
const controller = new AbortController();
|
|
72
|
+
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
73
|
+
let res;
|
|
74
|
+
try {
|
|
75
|
+
res = await fetch(endpoint, {
|
|
76
|
+
method: 'POST',
|
|
77
|
+
headers: {
|
|
78
|
+
'Content-Type': 'application/json',
|
|
79
|
+
// The only place the credential appears. Not logged, not echoed.
|
|
80
|
+
Authorization: `Bearer ${cred.token}`,
|
|
81
|
+
},
|
|
82
|
+
body: JSON.stringify({ verb, ...payload }),
|
|
83
|
+
signal: controller.signal,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
88
|
+
return {
|
|
89
|
+
error: `Could not reach the post office at ${endpoint}: ${detail}`,
|
|
90
|
+
code: 'HQ_UNAVAILABLE',
|
|
91
|
+
hint: 'Check the host resolves and is reachable. Note hq.decibelsystems.com has no DNS — ' +
|
|
92
|
+
`the working origin is ${DEFAULT_HQ_URL}.`,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
clearTimeout(timer);
|
|
97
|
+
}
|
|
98
|
+
const text = await res.text();
|
|
99
|
+
let body;
|
|
100
|
+
try {
|
|
101
|
+
body = JSON.parse(text);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return {
|
|
105
|
+
error: `Post office returned ${res.status} with a non-JSON body: ${text.slice(0, 200)}`,
|
|
106
|
+
code: 'HQ_UNAVAILABLE',
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (res.ok) {
|
|
110
|
+
log(`PostOffice: ${verb} ok`);
|
|
111
|
+
return body;
|
|
112
|
+
}
|
|
113
|
+
// The far side attaches `detail` to rejections that came from Postgres —
|
|
114
|
+
// a CHECK bound, a type mismatch, a missing FK. That detail IS the
|
|
115
|
+
// actionable half: "thread_rejected" says nothing, while
|
|
116
|
+
// 'invalid input syntax for type uuid: "decibel-tools-mcp"' says exactly
|
|
117
|
+
// what to pass instead. Dropping it was the first thing that cost a
|
|
118
|
+
// round-trip attempt to diagnose.
|
|
119
|
+
const base = typeof body.error === 'string' ? body.error : `HTTP ${res.status}`;
|
|
120
|
+
const detail = typeof body.detail === 'string' ? body.detail : undefined;
|
|
121
|
+
const message = detail ? `${base}: ${detail}` : base;
|
|
122
|
+
if (res.status === 401) {
|
|
123
|
+
return {
|
|
124
|
+
error: `The post office rejected this agent's credential: ${message}`,
|
|
125
|
+
code: 'HQ_UNAUTHORIZED',
|
|
126
|
+
hint: 'The token is wrong, revoked, or expired. Tokens are stored as a sha256 and cannot be ' +
|
|
127
|
+
'recovered — issue a new one with hq.issue_agent_token and replace DECIBEL_HQ_TOKEN.',
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
if (res.status === 403) {
|
|
131
|
+
const required = typeof body.required === 'string' ? body.required : 'a scope';
|
|
132
|
+
return {
|
|
133
|
+
error: `This credential lacks ${required}.`,
|
|
134
|
+
code: 'HQ_FORBIDDEN',
|
|
135
|
+
hint: 'Reads need postoffice.read and writes need postoffice.write. Re-issue with the scope.',
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
if (res.status === 404) {
|
|
139
|
+
return { error: message, code: 'HQ_NOT_FOUND' };
|
|
140
|
+
}
|
|
141
|
+
if (res.status === 400) {
|
|
142
|
+
const supported = Array.isArray(body.supported)
|
|
143
|
+
? ` Supported verbs: ${body.supported.join(', ')}.`
|
|
144
|
+
: '';
|
|
145
|
+
return { error: `${message}${supported}`, code: 'HQ_REJECTED' };
|
|
146
|
+
}
|
|
147
|
+
return { error: `Post office error (${res.status}): ${message}`, code: 'HQ_UNAVAILABLE' };
|
|
148
|
+
}
|
|
149
|
+
// ============================================================================
|
|
150
|
+
// Verbs
|
|
151
|
+
// ============================================================================
|
|
152
|
+
export function agentsList() {
|
|
153
|
+
return postOfficeCall('agents.list');
|
|
154
|
+
}
|
|
155
|
+
export function threadsOpen(input) {
|
|
156
|
+
return postOfficeCall('threads.open', {
|
|
157
|
+
subject: input.subject,
|
|
158
|
+
project: input.project,
|
|
159
|
+
intent: input.intent,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
export function messagesSend(input) {
|
|
163
|
+
return postOfficeCall('messages.send', { ...input });
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Read this agent's mail.
|
|
167
|
+
*
|
|
168
|
+
* `status` is deliberately NOT defaulted, and polling must not set it to
|
|
169
|
+
* 'sent'. The far side marks sent -> read as a side effect of reading, so a
|
|
170
|
+
* mailbox query filtered to status='sent' never returns a message twice: a
|
|
171
|
+
* reader that fetches and then dies before acting has silently consumed it,
|
|
172
|
+
* and no restart recovers it. Unfiltered, the same message comes back as
|
|
173
|
+
* 'read' and can still be acted on.
|
|
174
|
+
*
|
|
175
|
+
* That is the whole reason read and ack are separate verbs — at-least-once
|
|
176
|
+
* beats at-most-once here, because a duplicated message costs a minute and a
|
|
177
|
+
* dropped handoff stalls work invisibly.
|
|
178
|
+
*/
|
|
179
|
+
export function messagesRead(input = {}) {
|
|
180
|
+
const payload = {};
|
|
181
|
+
if (input.thread)
|
|
182
|
+
payload.thread = input.thread;
|
|
183
|
+
if (input.status)
|
|
184
|
+
payload.status = input.status;
|
|
185
|
+
if (input.limit)
|
|
186
|
+
payload.limit = input.limit;
|
|
187
|
+
return postOfficeCall('messages.read', payload);
|
|
188
|
+
}
|
|
189
|
+
/** Idempotent by construction on the far side: acking twice is not an error. */
|
|
190
|
+
export function messagesAck(input) {
|
|
191
|
+
return postOfficeCall('messages.ack', { message: input.message });
|
|
192
|
+
}
|
|
193
|
+
export function handoffRequest(input) {
|
|
194
|
+
return postOfficeCall('handoff.request', { ...input });
|
|
195
|
+
}
|
|
196
|
+
export function handoffRespond(input) {
|
|
197
|
+
return postOfficeCall('handoff.respond', { ...input });
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=postoffice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postoffice.js","sourceRoot":"","sources":["../../src/tools/postoffice.ts"],"names":[],"mappings":"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"}
|
|
@@ -31,6 +31,13 @@ export interface ListProvenanceInput {
|
|
|
31
31
|
export interface ListProvenanceOutput {
|
|
32
32
|
events: ProvenanceEvent[];
|
|
33
33
|
total_count: number;
|
|
34
|
+
/**
|
|
35
|
+
* Records that could not be read or parsed and are therefore absent from
|
|
36
|
+
* `events`. Zero on a healthy store. Present so that a short list is
|
|
37
|
+
* detectable — an empty result with unreadable_count > 0 means "could not
|
|
38
|
+
* read", which is a different fact from "no activity".
|
|
39
|
+
*/
|
|
40
|
+
unreadable_count: number;
|
|
34
41
|
}
|
|
35
42
|
export interface ProjectResolutionError {
|
|
36
43
|
error: 'project_resolution_failed';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provenance.d.ts","sourceRoot":"","sources":["../../src/tools/provenance.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,IAAI,GAAG,QAAQ,CAAC;AAClD,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;AACjH,MAAM,MAAM,UAAU,GAClB,kBAAkB,GAClB,YAAY,GACZ,YAAY,GACZ,eAAe,GACf,gBAAgB,GAChB,YAAY,GACZ,WAAW,GACX,SAAS,CAAC;AAEd,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,SAAS,CAAC;IACtB,MAAM,EAAE,gBAAgB,CAAC;IACzB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,EAAE,UAAU,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,gBAAgB,CAAC;IACzB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,EAAE,UAAU,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"provenance.d.ts","sourceRoot":"","sources":["../../src/tools/provenance.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,IAAI,GAAG,QAAQ,CAAC;AAClD,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;AACjH,MAAM,MAAM,UAAU,GAClB,kBAAkB,GAClB,YAAY,GACZ,YAAY,GACZ,eAAe,GACf,gBAAgB,GAChB,YAAY,GACZ,WAAW,GACX,SAAS,CAAC;AAEd,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,SAAS,CAAC;IACtB,MAAM,EAAE,gBAAgB,CAAC;IACzB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,EAAE,UAAU,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,gBAAgB,CAAC;IACzB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,EAAE,UAAU,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,2BAA2B,CAAC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAeD;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAMxC;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGnD;AAsBD;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAc1C;AAgDD;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,mBAAmB,EAC1B,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,GAAG,sBAAsB,CAAC,CAyC1C;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,mBAAmB,GACzB,OAAO,CAAC,oBAAoB,GAAG,sBAAsB,CAAC,CA0ExD;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,GAAG,sBAAsB,CAAC,CAgB1C"}
|
package/dist/tools/provenance.js
CHANGED
|
@@ -173,26 +173,51 @@ export async function listProvenance(input) {
|
|
|
173
173
|
const eventsDir = resolved.subPath('provenance', 'events');
|
|
174
174
|
const limit = input.limit || 50;
|
|
175
175
|
let events = [];
|
|
176
|
+
// A missing directory means "no events yet" and is the only failure that may
|
|
177
|
+
// be reported as emptiness. Anything else — EMFILE under a fan-out, EACCES, a
|
|
178
|
+
// bad mount — must reach the caller: this used to be a bare catch around both
|
|
179
|
+
// the readdir AND the read loop, so any of those returned `{events: [],
|
|
180
|
+
// total_count: 0}` through a SUCCESS envelope, indistinguishable from a
|
|
181
|
+
// project with no activity. HQ measured ten of thirty-four projects reporting
|
|
182
|
+
// empty that demonstrably had events (2026-08-30).
|
|
183
|
+
let yamlFiles;
|
|
176
184
|
try {
|
|
177
185
|
const files = await fs.readdir(eventsDir);
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
continue;
|
|
184
|
-
// Apply filters
|
|
185
|
-
if (input.artifact_ref && !event.artifact_refs.includes(input.artifact_ref)) {
|
|
186
|
-
continue;
|
|
187
|
-
}
|
|
188
|
-
if (input.actor_id && event.actor_id !== input.actor_id) {
|
|
189
|
-
continue;
|
|
190
|
-
}
|
|
191
|
-
events.push(event);
|
|
186
|
+
yamlFiles = files.filter(f => f.endsWith('.yml') && f.startsWith('PROV-'));
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
if (err.code === 'ENOENT') {
|
|
190
|
+
return { events: [], total_count: 0, unreadable_count: 0 };
|
|
192
191
|
}
|
|
192
|
+
throw err;
|
|
193
193
|
}
|
|
194
|
-
|
|
195
|
-
|
|
194
|
+
// Per-file failures do not abort the listing — one corrupt record should not
|
|
195
|
+
// hide the other ninety-nine — but they are counted, because a silently short
|
|
196
|
+
// list is a lie a caller cannot detect. `parseProvenanceFile` also returns
|
|
197
|
+
// null for a record missing required fields; that is the same loss.
|
|
198
|
+
let unreadable = 0;
|
|
199
|
+
for (const file of yamlFiles) {
|
|
200
|
+
const filePath = path.join(eventsDir, file);
|
|
201
|
+
let event;
|
|
202
|
+
try {
|
|
203
|
+
event = await parseProvenanceFile(filePath);
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
unreadable++;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (!event) {
|
|
210
|
+
unreadable++;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
// Apply filters
|
|
214
|
+
if (input.artifact_ref && !event.artifact_refs.includes(input.artifact_ref)) {
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
if (input.actor_id && event.actor_id !== input.actor_id) {
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
events.push(event);
|
|
196
221
|
}
|
|
197
222
|
const totalCount = events.length;
|
|
198
223
|
// Sort by timestamp descending (newest first)
|
|
@@ -202,6 +227,7 @@ export async function listProvenance(input) {
|
|
|
202
227
|
return {
|
|
203
228
|
events,
|
|
204
229
|
total_count: totalCount,
|
|
230
|
+
unreadable_count: unreadable,
|
|
205
231
|
};
|
|
206
232
|
}
|
|
207
233
|
/**
|