@damian87/omp 0.8.0 → 0.9.2
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/.github/skills/slack/SKILL.md +82 -0
- package/README.md +36 -38
- package/catalog/capabilities.json +46 -0
- package/catalog/skills-general.json +26 -0
- package/dist/src/cli.js +58 -5
- package/dist/src/cli.js.map +1 -1
- package/dist/src/copilot/version.js +10 -0
- package/dist/src/copilot/version.js.map +1 -1
- package/dist/src/env/init.d.ts +6 -0
- package/dist/src/env/init.js +18 -0
- package/dist/src/env/init.js.map +1 -1
- package/dist/src/gateway/notify.d.ts +35 -0
- package/dist/src/gateway/notify.js +261 -0
- package/dist/src/gateway/notify.js.map +1 -0
- package/dist/src/gateway/target-parser.d.ts +76 -0
- package/dist/src/gateway/target-parser.js +105 -0
- package/dist/src/gateway/target-parser.js.map +1 -0
- package/dist/src/schedule/commands.js +1 -0
- package/dist/src/schedule/commands.js.map +1 -1
- package/dist/src/schedule/runner.d.ts +9 -0
- package/dist/src/schedule/runner.js +31 -1
- package/dist/src/schedule/runner.js.map +1 -1
- package/dist/src/schedule/types.d.ts +9 -0
- package/docs/slack-setup.md +33 -0
- package/package.json +11 -3
- package/plugin.json +12 -4
- package/scripts/lib/version-check.mjs +3 -0
- package/dist/src/mcp/server.d.ts +0 -10
- package/dist/src/mcp/server.js +0 -44
- package/dist/src/mcp/server.js.map +0 -1
- package/dist/src/mcp/tools/daily-log.d.ts +0 -2
- package/dist/src/mcp/tools/daily-log.js +0 -148
- package/dist/src/mcp/tools/daily-log.js.map +0 -1
- package/dist/src/mcp/tools/index.d.ts +0 -9
- package/dist/src/mcp/tools/index.js +0 -15
- package/dist/src/mcp/tools/index.js.map +0 -1
- package/dist/src/mcp/tools/notepad.d.ts +0 -2
- package/dist/src/mcp/tools/notepad.js +0 -135
- package/dist/src/mcp/tools/notepad.js.map +0 -1
- package/dist/src/mcp/tools/project-memory.d.ts +0 -2
- package/dist/src/mcp/tools/project-memory.js +0 -91
- package/dist/src/mcp/tools/project-memory.js.map +0 -1
- package/dist/src/mcp/tools/shared-memory.d.ts +0 -2
- package/dist/src/mcp/tools/shared-memory.js +0 -148
- package/dist/src/mcp/tools/shared-memory.js.map +0 -1
- package/dist/src/mcp/tools/state.d.ts +0 -2
- package/dist/src/mcp/tools/state.js +0 -107
- package/dist/src/mcp/tools/state.js.map +0 -1
- package/dist/src/mcp/tools/trace.d.ts +0 -10
- package/dist/src/mcp/tools/trace.js +0 -102
- package/dist/src/mcp/tools/trace.js.map +0 -1
- package/dist/src/mcp/types.d.ts +0 -29
- package/dist/src/mcp/types.js +0 -7
- package/dist/src/mcp/types.js.map +0 -1
- package/dist/test/catalog.test.d.ts +0 -1
- package/dist/test/catalog.test.js +0 -21
- package/dist/test/catalog.test.js.map +0 -1
- package/dist/test/jira.test.d.ts +0 -1
- package/dist/test/jira.test.js +0 -26
- package/dist/test/jira.test.js.map +0 -1
- package/dist/test/lint.test.d.ts +0 -1
- package/dist/test/lint.test.js +0 -9
- package/dist/test/lint.test.js.map +0 -1
- package/dist/test/sync.test.d.ts +0 -1
- package/dist/test/sync.test.js +0 -15
- package/dist/test/sync.test.js.map +0 -1
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outbound Slack notifier — Hermes-style. No daemon. No socket. Each call is
|
|
3
|
+
* a stateless POST to Slack's REST API.
|
|
4
|
+
*
|
|
5
|
+
* Resolution model (mirrors apps/hermes-agent/tools/send_message_tool.py):
|
|
6
|
+
* 1. Caller passes `target` OR we read `SLACK_HOME_CHANNEL` from env.
|
|
7
|
+
* 2. If the resolved Slack ID is a user-id (U…), we call
|
|
8
|
+
* `conversations.open` once to get the corresponding D… IM channel.
|
|
9
|
+
* 3. POST to `chat.postMessage` with the (D…/C…/G…) channel id.
|
|
10
|
+
*
|
|
11
|
+
* Retry: bounded exponential backoff on 429 (rate limit) and 5xx. Other Slack
|
|
12
|
+
* errors return immediately with the typed reason code so callers (cron) can
|
|
13
|
+
* record dropped payloads to a side log without hammering Slack.
|
|
14
|
+
*/
|
|
15
|
+
import { parseTarget, parseSlackRef } from "./target-parser.js";
|
|
16
|
+
const SLACK_POST_URL = "https://slack.com/api/chat.postMessage";
|
|
17
|
+
const SLACK_OPEN_URL = "https://slack.com/api/conversations.open";
|
|
18
|
+
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
19
|
+
const MAX_ATTEMPTS = 3;
|
|
20
|
+
/**
|
|
21
|
+
* Send a Slack message. Library entry point — never throws. Returns a
|
|
22
|
+
* structured result so callers (cron / `/slack send` skill / CLI) decide
|
|
23
|
+
* how to surface or persist failures.
|
|
24
|
+
*/
|
|
25
|
+
export async function notify(opts, deps = {}) {
|
|
26
|
+
const env = deps.env ?? process.env;
|
|
27
|
+
const doFetch = deps.fetch ?? fetch;
|
|
28
|
+
const sleep = deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
29
|
+
const text = (opts.text ?? "").toString();
|
|
30
|
+
if (!text.trim()) {
|
|
31
|
+
return { ok: false, code: "POST_FAILED", reason: "text is empty" };
|
|
32
|
+
}
|
|
33
|
+
const token = (env.SLACK_BOT_TOKEN ?? "").trim();
|
|
34
|
+
if (!token) {
|
|
35
|
+
return { ok: false, code: "MISSING_TOKEN", reason: "SLACK_BOT_TOKEN is not set" };
|
|
36
|
+
}
|
|
37
|
+
// 1. Resolve target.
|
|
38
|
+
let target;
|
|
39
|
+
if (opts.target && opts.target.trim()) {
|
|
40
|
+
const parsed = parseTarget(opts.target);
|
|
41
|
+
if (!parsed.ok)
|
|
42
|
+
return { ok: false, code: "BAD_TARGET", reason: parsed.error };
|
|
43
|
+
target = parsed.target;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
const home = (env.SLACK_HOME_CHANNEL ?? "").trim();
|
|
47
|
+
if (!home) {
|
|
48
|
+
return {
|
|
49
|
+
ok: false,
|
|
50
|
+
code: "MISSING_TARGET",
|
|
51
|
+
reason: "no --target and SLACK_HOME_CHANNEL is unset; set one via `omp env init` or pass --target slack:C0…",
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const parsed = parseSlackRef(home);
|
|
55
|
+
if (!parsed.ok) {
|
|
56
|
+
return {
|
|
57
|
+
ok: false,
|
|
58
|
+
code: "BAD_HOME_CHANNEL",
|
|
59
|
+
reason: `SLACK_HOME_CHANNEL=${home}: ${parsed.error}`,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
target = parsed.target;
|
|
63
|
+
}
|
|
64
|
+
// Validate an explicit --thread-ts the same way we validate :thread_ts
|
|
65
|
+
// suffixes in the target string. Without this, a typo via the flag path
|
|
66
|
+
// bypasses parser validation and Slack reports an opaque error at runtime.
|
|
67
|
+
if (opts.threadTs && !/^[0-9]+\.[0-9]+$/.test(opts.threadTs)) {
|
|
68
|
+
return {
|
|
69
|
+
ok: false,
|
|
70
|
+
code: "BAD_TARGET",
|
|
71
|
+
reason: `threadTs "${opts.threadTs}" is not a Slack timestamp (expected digits.digits)`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
// One absolute deadline for the whole notify call — shared across
|
|
75
|
+
// conversations.open + chat.postMessage so a U-target send can't quietly
|
|
76
|
+
// take 2× the documented budget.
|
|
77
|
+
const deadline = Date.now() + (opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
78
|
+
// 2. If user-id, resolve to a DM channel via conversations.open.
|
|
79
|
+
let channelId = target.id;
|
|
80
|
+
let openedIm = false;
|
|
81
|
+
if (target.kind === "user") {
|
|
82
|
+
const opened = await openIm(target.id, { token, doFetch, sleep, deadline });
|
|
83
|
+
if (!opened.ok)
|
|
84
|
+
return opened;
|
|
85
|
+
channelId = opened.channel;
|
|
86
|
+
openedIm = true;
|
|
87
|
+
}
|
|
88
|
+
// 3. Post.
|
|
89
|
+
const threadTs = opts.threadTs ?? target.threadTs;
|
|
90
|
+
return await postMessage({
|
|
91
|
+
token,
|
|
92
|
+
channel: channelId,
|
|
93
|
+
text,
|
|
94
|
+
threadTs,
|
|
95
|
+
doFetch,
|
|
96
|
+
sleep,
|
|
97
|
+
openedIm,
|
|
98
|
+
deadline,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
async function openIm(userId, args) {
|
|
102
|
+
const r = await callSlack({
|
|
103
|
+
url: SLACK_OPEN_URL,
|
|
104
|
+
body: { users: userId },
|
|
105
|
+
...args,
|
|
106
|
+
});
|
|
107
|
+
if (!r.ok) {
|
|
108
|
+
if (r.code === "RATE_LIMITED" || r.code === "TIMEOUT" || r.code === "NETWORK_ERROR") {
|
|
109
|
+
return r;
|
|
110
|
+
}
|
|
111
|
+
return { ok: false, code: "OPEN_FAILED", reason: r.reason };
|
|
112
|
+
}
|
|
113
|
+
const channel = r.payload?.channel?.id;
|
|
114
|
+
if (!channel) {
|
|
115
|
+
return { ok: false, code: "OPEN_FAILED", reason: "conversations.open returned no channel.id" };
|
|
116
|
+
}
|
|
117
|
+
return { ok: true, channel };
|
|
118
|
+
}
|
|
119
|
+
async function postMessage(args) {
|
|
120
|
+
const body = {
|
|
121
|
+
channel: args.channel,
|
|
122
|
+
text: args.text,
|
|
123
|
+
};
|
|
124
|
+
if (args.threadTs)
|
|
125
|
+
body.thread_ts = args.threadTs;
|
|
126
|
+
const r = await callSlack({ url: SLACK_POST_URL, body, ...args });
|
|
127
|
+
if (!r.ok)
|
|
128
|
+
return r;
|
|
129
|
+
const ts = r.payload?.ts ?? "";
|
|
130
|
+
return { ok: true, channel: args.channel, ts, openedIm: args.openedIm };
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Single Slack API call with bounded retry. Treats 429 + 5xx as retryable
|
|
134
|
+
* (exponential backoff bounded by `timeoutMs`). Slack-level `ok:false`
|
|
135
|
+
* payloads return immediately as POST_FAILED — those are deterministic
|
|
136
|
+
* (invalid token / channel_not_found / not_in_channel etc).
|
|
137
|
+
*/
|
|
138
|
+
async function callSlack(args) {
|
|
139
|
+
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
|
|
140
|
+
const remaining = args.deadline - Date.now();
|
|
141
|
+
if (remaining <= 0) {
|
|
142
|
+
return { ok: false, code: "TIMEOUT", reason: `gave up after deadline` };
|
|
143
|
+
}
|
|
144
|
+
let res;
|
|
145
|
+
try {
|
|
146
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
147
|
+
res = await args.doFetch(args.url, {
|
|
148
|
+
method: "POST",
|
|
149
|
+
headers: {
|
|
150
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
151
|
+
Authorization: `Bearer ${args.token}`,
|
|
152
|
+
},
|
|
153
|
+
body: JSON.stringify(args.body),
|
|
154
|
+
signal: AbortSignal.timeout(Math.min(remaining, 5_000)),
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
const msg = redact(err instanceof Error ? err.message : String(err), args.token);
|
|
159
|
+
if (/abort|timeout/i.test(msg)) {
|
|
160
|
+
return { ok: false, code: "TIMEOUT", reason: msg };
|
|
161
|
+
}
|
|
162
|
+
// Network blip — try again if we have budget.
|
|
163
|
+
const sleepMs = Math.min(backoffMs(attempt), Math.max(args.deadline - Date.now() - 50, 0));
|
|
164
|
+
if (attempt < MAX_ATTEMPTS - 1 && sleepMs > 0) {
|
|
165
|
+
await args.sleep(sleepMs);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
return { ok: false, code: "NETWORK_ERROR", reason: msg };
|
|
169
|
+
}
|
|
170
|
+
// 429 → wait per Retry-After header if present; otherwise exponential.
|
|
171
|
+
if (res.status === 429) {
|
|
172
|
+
const retryAfter = Number(res.headers.get("retry-after") ?? 1);
|
|
173
|
+
const sleepBudget = Math.max(args.deadline - Date.now() - 100, 0);
|
|
174
|
+
const sleepMs = Math.min(retryAfter * 1000, sleepBudget);
|
|
175
|
+
if (attempt < MAX_ATTEMPTS - 1 && sleepMs >= 0 && sleepBudget > 0) {
|
|
176
|
+
await args.sleep(sleepMs);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
return { ok: false, code: "RATE_LIMITED", reason: `429 after ${attempt + 1} attempt(s)` };
|
|
180
|
+
}
|
|
181
|
+
// 5xx → retry.
|
|
182
|
+
if (res.status >= 500 && res.status < 600) {
|
|
183
|
+
const sleepMs = Math.min(backoffMs(attempt), Math.max(args.deadline - Date.now() - 50, 0));
|
|
184
|
+
if (attempt < MAX_ATTEMPTS - 1 && sleepMs > 0) {
|
|
185
|
+
await args.sleep(sleepMs);
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
return { ok: false, code: "POST_FAILED", reason: `slack ${res.status} after ${attempt + 1} attempt(s)` };
|
|
189
|
+
}
|
|
190
|
+
// Anything else: parse the body and dispatch on Slack's own ok flag.
|
|
191
|
+
let payload;
|
|
192
|
+
try {
|
|
193
|
+
payload = (await res.json());
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
return { ok: false, code: "POST_FAILED", reason: `slack ${res.status}: non-JSON response` };
|
|
197
|
+
}
|
|
198
|
+
if (payload.ok === true)
|
|
199
|
+
return { ok: true, payload };
|
|
200
|
+
// Slack's documented schema has `error` as a string, but proxies / WAFs /
|
|
201
|
+
// wrong endpoints can return object / array / null. Coerce defensively
|
|
202
|
+
// before redacting — the public contract is never-throws.
|
|
203
|
+
const rawError = payload.error;
|
|
204
|
+
const reasonRaw = coerceErrorReason(rawError);
|
|
205
|
+
const reason = redact(reasonRaw, args.token);
|
|
206
|
+
// Slack uses `ratelimited` (no underscore) for rate-limit errors when not
|
|
207
|
+
// surfaced as HTTP 429. Treat as RATE_LIMITED so callers can back off.
|
|
208
|
+
if (reasonRaw === "ratelimited" || reasonRaw === "rate_limited") {
|
|
209
|
+
return { ok: false, code: "RATE_LIMITED", reason };
|
|
210
|
+
}
|
|
211
|
+
return { ok: false, code: "POST_FAILED", reason };
|
|
212
|
+
}
|
|
213
|
+
return { ok: false, code: "POST_FAILED", reason: "exhausted retries" };
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Coerce a Slack error field of unknown shape to a string. Slack documents
|
|
217
|
+
* `error: string`, but proxies/WAFs/mis-pointed endpoints can return objects,
|
|
218
|
+
* arrays, or null. We must NOT throw — the caller's never-throws guarantee
|
|
219
|
+
* is part of the public contract.
|
|
220
|
+
*/
|
|
221
|
+
function coerceErrorReason(raw) {
|
|
222
|
+
if (raw == null)
|
|
223
|
+
return "slack returned ok:false";
|
|
224
|
+
if (typeof raw === "string")
|
|
225
|
+
return raw;
|
|
226
|
+
if (typeof raw === "number" || typeof raw === "boolean")
|
|
227
|
+
return String(raw);
|
|
228
|
+
try {
|
|
229
|
+
return JSON.stringify(raw);
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
return "slack returned ok:false (unserializable error field)";
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Strip the bot token (and Bearer-prefix patterns) from any string that's
|
|
237
|
+
* about to be returned in `reason` or logged. Cheap belt-and-braces guard:
|
|
238
|
+
* Slack itself never echoes our token, but a fetch / abort / DNS error could
|
|
239
|
+
* contain the request URL or headers depending on the runtime, and any such
|
|
240
|
+
* leak would land in the schedule runner's stderr log.
|
|
241
|
+
*/
|
|
242
|
+
function redact(s, token) {
|
|
243
|
+
let out = s;
|
|
244
|
+
if (token) {
|
|
245
|
+
// Replace literal token wherever it appears.
|
|
246
|
+
out = out.split(token).join("[REDACTED]");
|
|
247
|
+
}
|
|
248
|
+
// Strip generic Bearer-token patterns that some fetch errors include.
|
|
249
|
+
out = out.replace(/Bearer\s+[A-Za-z0-9-._~+/]+=*/g, "Bearer [REDACTED]");
|
|
250
|
+
// Strip Slack-format tokens that might appear in payloads. Covers:
|
|
251
|
+
// xox[a/b/e/p/r/s]- (legacy access / bot / refresh / user / config / signing)
|
|
252
|
+
// xapp- (app-level tokens — what `omp gateway serve` uses)
|
|
253
|
+
out = out.replace(/xox[a-z]-[A-Za-z0-9-]+/gi, "[REDACTED]");
|
|
254
|
+
out = out.replace(/xapp-[A-Za-z0-9-]+/gi, "[REDACTED]");
|
|
255
|
+
return out;
|
|
256
|
+
}
|
|
257
|
+
function backoffMs(attempt) {
|
|
258
|
+
// 250ms, 500ms, 1000ms — bounded so a misbehaving Slack doesn't stall cron forever.
|
|
259
|
+
return Math.min(250 * 2 ** attempt, 1_000);
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=notify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notify.js","sourceRoot":"","sources":["../../../src/gateway/notify.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse outbound notification targets.
|
|
3
|
+
*
|
|
4
|
+
* Target grammar (Hermes-mirror — see apps/hermes-agent/tools/send_message_tool.py:21-46):
|
|
5
|
+
*
|
|
6
|
+
* "<platform>:<ref>" → explicit per-call target
|
|
7
|
+
*
|
|
8
|
+
* Bare-platform fallback (`<platform>` with no `:<ref>`) is NOT implemented in
|
|
9
|
+
* this parser. The notify() caller layer handles the "no target → env default"
|
|
10
|
+
* decision by passing undefined/empty as the target and reading
|
|
11
|
+
* `SLACK_HOME_CHANNEL` directly — it never calls `parseTarget("slack")`.
|
|
12
|
+
*
|
|
13
|
+
* For slice 1 the only platform is "slack". <ref> for slack is a 9+ char
|
|
14
|
+
* uppercase alphanumeric ID prefixed with one of:
|
|
15
|
+
* C — public channel
|
|
16
|
+
* G — private channel ("group")
|
|
17
|
+
* D — direct message conversation
|
|
18
|
+
* U — user (must be conversations.open'd to a D… before chat.postMessage;
|
|
19
|
+
* the caller is responsible for that resolution)
|
|
20
|
+
*
|
|
21
|
+
* Optional thread suffix: "<ref>:<thread_ts>" pins the post to an existing
|
|
22
|
+
* thread in that conversation. Not all kinds support threading sensibly, but
|
|
23
|
+
* the parser accepts it for any non-user kind.
|
|
24
|
+
*
|
|
25
|
+
* NOT supported in this pass: user IDs with embedded thread suffixes (no
|
|
26
|
+
* coherent meaning until U→D resolution); Hermes-style multi-platform
|
|
27
|
+
* regexes for telegram/discord/feishu (those land in slice 2+).
|
|
28
|
+
*/
|
|
29
|
+
/** Slack ID after the `slack:` prefix. */
|
|
30
|
+
export declare const SLACK_ID_RE: RegExp;
|
|
31
|
+
/**
|
|
32
|
+
* Slack ID + optional thread suffix `:<thread_ts>`.
|
|
33
|
+
*
|
|
34
|
+
* `thread_ts` must look like Slack's canonical message timestamp shape
|
|
35
|
+
* (`<seconds>.<microseconds>` — digits-only). Anything else is rejected here
|
|
36
|
+
* so the CLI / schedule add validators catch typos before they reach Slack.
|
|
37
|
+
*/
|
|
38
|
+
export declare const SLACK_TARGET_RE: RegExp;
|
|
39
|
+
export type SlackTargetKind = "channel" | "group" | "dm" | "user";
|
|
40
|
+
export interface SlackTarget {
|
|
41
|
+
platform: "slack";
|
|
42
|
+
kind: SlackTargetKind;
|
|
43
|
+
/**
|
|
44
|
+
* The raw Slack ID (`C…`/`G…`/`D…`/`U…`). For user targets, the caller
|
|
45
|
+
* must resolve to a D-ID via conversations.open before posting.
|
|
46
|
+
*/
|
|
47
|
+
id: string;
|
|
48
|
+
/** Optional `thread_ts` for threaded posts. */
|
|
49
|
+
threadTs?: string;
|
|
50
|
+
}
|
|
51
|
+
export type ParsedTarget = SlackTarget;
|
|
52
|
+
export interface ParseError {
|
|
53
|
+
ok: false;
|
|
54
|
+
error: string;
|
|
55
|
+
}
|
|
56
|
+
export type ParseResult = {
|
|
57
|
+
ok: true;
|
|
58
|
+
target: ParsedTarget;
|
|
59
|
+
} | ParseError;
|
|
60
|
+
/**
|
|
61
|
+
* Parse a target string of the form `<platform>:<ref>`. Returns either a
|
|
62
|
+
* structured target or a friendly error. Pure — no I/O.
|
|
63
|
+
*/
|
|
64
|
+
export declare function parseTarget(raw: string): ParseResult;
|
|
65
|
+
/**
|
|
66
|
+
* Parse just the slack-side `<ref>` (the part after `slack:`). Useful when a
|
|
67
|
+
* caller has already established platform context (e.g. `SLACK_HOME_CHANNEL`
|
|
68
|
+
* is set without a platform prefix).
|
|
69
|
+
*/
|
|
70
|
+
export declare function parseSlackRef(ref: string): ParseResult;
|
|
71
|
+
/**
|
|
72
|
+
* Best-effort check for "looks like a Slack ID" without committing to a
|
|
73
|
+
* specific kind — used by config validators to nudge users about typos
|
|
74
|
+
* before any network call.
|
|
75
|
+
*/
|
|
76
|
+
export declare function looksLikeSlackId(value: string): boolean;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse outbound notification targets.
|
|
3
|
+
*
|
|
4
|
+
* Target grammar (Hermes-mirror — see apps/hermes-agent/tools/send_message_tool.py:21-46):
|
|
5
|
+
*
|
|
6
|
+
* "<platform>:<ref>" → explicit per-call target
|
|
7
|
+
*
|
|
8
|
+
* Bare-platform fallback (`<platform>` with no `:<ref>`) is NOT implemented in
|
|
9
|
+
* this parser. The notify() caller layer handles the "no target → env default"
|
|
10
|
+
* decision by passing undefined/empty as the target and reading
|
|
11
|
+
* `SLACK_HOME_CHANNEL` directly — it never calls `parseTarget("slack")`.
|
|
12
|
+
*
|
|
13
|
+
* For slice 1 the only platform is "slack". <ref> for slack is a 9+ char
|
|
14
|
+
* uppercase alphanumeric ID prefixed with one of:
|
|
15
|
+
* C — public channel
|
|
16
|
+
* G — private channel ("group")
|
|
17
|
+
* D — direct message conversation
|
|
18
|
+
* U — user (must be conversations.open'd to a D… before chat.postMessage;
|
|
19
|
+
* the caller is responsible for that resolution)
|
|
20
|
+
*
|
|
21
|
+
* Optional thread suffix: "<ref>:<thread_ts>" pins the post to an existing
|
|
22
|
+
* thread in that conversation. Not all kinds support threading sensibly, but
|
|
23
|
+
* the parser accepts it for any non-user kind.
|
|
24
|
+
*
|
|
25
|
+
* NOT supported in this pass: user IDs with embedded thread suffixes (no
|
|
26
|
+
* coherent meaning until U→D resolution); Hermes-style multi-platform
|
|
27
|
+
* regexes for telegram/discord/feishu (those land in slice 2+).
|
|
28
|
+
*/
|
|
29
|
+
/** Slack ID after the `slack:` prefix. */
|
|
30
|
+
export const SLACK_ID_RE = /^([CGDU])([A-Z0-9]{8,})$/;
|
|
31
|
+
/**
|
|
32
|
+
* Slack ID + optional thread suffix `:<thread_ts>`.
|
|
33
|
+
*
|
|
34
|
+
* `thread_ts` must look like Slack's canonical message timestamp shape
|
|
35
|
+
* (`<seconds>.<microseconds>` — digits-only). Anything else is rejected here
|
|
36
|
+
* so the CLI / schedule add validators catch typos before they reach Slack.
|
|
37
|
+
*/
|
|
38
|
+
export const SLACK_TARGET_RE = /^([CGD])([A-Z0-9]{8,})(?::([0-9]+\.[0-9]+))?$|^(U)([A-Z0-9]{8,})$/;
|
|
39
|
+
const SLACK_KIND = {
|
|
40
|
+
C: "channel",
|
|
41
|
+
G: "group",
|
|
42
|
+
D: "dm",
|
|
43
|
+
U: "user",
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Parse a target string of the form `<platform>:<ref>`. Returns either a
|
|
47
|
+
* structured target or a friendly error. Pure — no I/O.
|
|
48
|
+
*/
|
|
49
|
+
export function parseTarget(raw) {
|
|
50
|
+
const trimmed = raw.trim();
|
|
51
|
+
if (!trimmed)
|
|
52
|
+
return { ok: false, error: "target is empty" };
|
|
53
|
+
const colon = trimmed.indexOf(":");
|
|
54
|
+
if (colon === -1) {
|
|
55
|
+
return {
|
|
56
|
+
ok: false,
|
|
57
|
+
error: `target "${trimmed}" missing ":<ref>"; e.g. slack:C0BOQV5434G or slack:U0123ABCD`,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const platform = trimmed.slice(0, colon).trim().toLowerCase();
|
|
61
|
+
const ref = trimmed.slice(colon + 1).trim();
|
|
62
|
+
if (platform !== "slack") {
|
|
63
|
+
return { ok: false, error: `unsupported platform "${platform}"; only "slack" today` };
|
|
64
|
+
}
|
|
65
|
+
if (!ref) {
|
|
66
|
+
return { ok: false, error: `slack target missing ID; e.g. slack:C0BOQV5434G` };
|
|
67
|
+
}
|
|
68
|
+
return parseSlackRef(ref);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Parse just the slack-side `<ref>` (the part after `slack:`). Useful when a
|
|
72
|
+
* caller has already established platform context (e.g. `SLACK_HOME_CHANNEL`
|
|
73
|
+
* is set without a platform prefix).
|
|
74
|
+
*/
|
|
75
|
+
export function parseSlackRef(ref) {
|
|
76
|
+
const m = ref.match(SLACK_TARGET_RE);
|
|
77
|
+
if (!m) {
|
|
78
|
+
return {
|
|
79
|
+
ok: false,
|
|
80
|
+
error: `not a Slack ID: "${ref}". Expected C…/G…/D…/U… plus 8+ uppercase alphanumeric chars (optional :thread_ts for channels)`,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
// Two alternatives in the regex; pick whichever matched.
|
|
84
|
+
const prefix = (m[1] ?? m[4]);
|
|
85
|
+
const body = (m[2] ?? m[5]);
|
|
86
|
+
const threadTs = m[3];
|
|
87
|
+
return {
|
|
88
|
+
ok: true,
|
|
89
|
+
target: {
|
|
90
|
+
platform: "slack",
|
|
91
|
+
kind: SLACK_KIND[prefix],
|
|
92
|
+
id: `${prefix}${body}`,
|
|
93
|
+
threadTs,
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Best-effort check for "looks like a Slack ID" without committing to a
|
|
99
|
+
* specific kind — used by config validators to nudge users about typos
|
|
100
|
+
* before any network call.
|
|
101
|
+
*/
|
|
102
|
+
export function looksLikeSlackId(value) {
|
|
103
|
+
return SLACK_ID_RE.test(value.trim());
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=target-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"target-parser.js","sourceRoot":"","sources":["../../../src/gateway/target-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,0CAA0C;AAC1C,MAAM,CAAC,MAAM,WAAW,GAAG,0BAA0B,CAAC;AAEtD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAC1B,mEAAmE,CAAC;AAyBtE,MAAM,UAAU,GAAoC;IAClD,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,OAAO;IACV,CAAC,EAAE,IAAI;IACP,CAAC,EAAE,MAAM;CACV,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAE7D,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;QACjB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,WAAW,OAAO,+DAA+D;SACzF,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC9D,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAE5C,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,yBAAyB,QAAQ,uBAAuB,EAAE,CAAC;IACxF,CAAC;IACD,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,iDAAiD,EAAE,CAAC;IACjF,CAAC;IACD,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IACrC,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,oBAAoB,GAAG,iGAAiG;SAChI,CAAC;IACJ,CAAC;IAED,yDAAyD;IACzD,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAA4B,CAAC;IACzD,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAW,CAAC;IACtC,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAEtB,OAAO;QACL,EAAE,EAAE,IAAI;QACR,MAAM,EAAE;YACN,QAAQ,EAAE,OAAO;YACjB,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC;YACxB,EAAE,EAAE,GAAG,MAAM,GAAG,IAAI,EAAE;YACtB,QAAQ;SACT;KACF,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,OAAO,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -64,6 +64,7 @@ export function addScheduleJob(stateCwd, opts) {
|
|
|
64
64
|
backend: "crontab",
|
|
65
65
|
ompBinPath: resolveOmpBinPath(),
|
|
66
66
|
active: true,
|
|
67
|
+
notifyTarget: opts.notifyTarget,
|
|
67
68
|
};
|
|
68
69
|
if (opts.dryRun) {
|
|
69
70
|
messages.push(`[dry-run] would install job "${job.id}" (cron ${job.cron}) for agent ${job.bin} in ${job.cwd}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../../src/schedule/commands.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../../src/schedule/commands.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,15 @@ import { type ScheduleJob, type ScheduleRunResult } from "./types.js";
|
|
|
3
3
|
export interface RunOptions {
|
|
4
4
|
/** Called when a job has expired (TTL passed or maxRuns reached) so the caller can uninstall the OS entry. */
|
|
5
5
|
onExpire?: (job: ScheduleJob) => void;
|
|
6
|
+
/**
|
|
7
|
+
* Override the notify implementation (tests). Defaults to `gateway/notify.notify`.
|
|
8
|
+
* Returning anything falsy is treated as a delivery failure; the runner only
|
|
9
|
+
* logs it to stderr — notify failures never propagate into the job result.
|
|
10
|
+
*/
|
|
11
|
+
notify?: (text: string, target: string) => Promise<{
|
|
12
|
+
ok: boolean;
|
|
13
|
+
reason?: string;
|
|
14
|
+
}>;
|
|
6
15
|
}
|
|
7
16
|
/** Execute one scheduled run (expiry check, overlap lock, timeout, log capture, result append). */
|
|
8
17
|
export declare function runScheduledJob(job: ScheduleJob, paths: SchedulePaths, opts?: RunOptions): Promise<ScheduleRunResult>;
|
|
@@ -91,6 +91,9 @@ export async function runScheduledJob(job, paths, opts = {}) {
|
|
|
91
91
|
const logDir = runLogDir(paths.logsDir, job.id);
|
|
92
92
|
mkdirSync(logDir, { recursive: true });
|
|
93
93
|
const logPath = join(logDir, `${timestampSlug()}.log`);
|
|
94
|
+
// Tracks whether the lock was already released before we entered `finally`,
|
|
95
|
+
// so we don't double-release after the notify hand-off below.
|
|
96
|
+
let lockReleased = false;
|
|
94
97
|
try {
|
|
95
98
|
const bin = resolveCopilotBin(job.bin);
|
|
96
99
|
const args = [];
|
|
@@ -142,10 +145,37 @@ export async function runScheduledJob(job, paths, opts = {}) {
|
|
|
142
145
|
child.on("close", (code) => finish(typeof code === "number" ? code : timedOut ? 124 : 1));
|
|
143
146
|
});
|
|
144
147
|
persist(result.status, result, true);
|
|
148
|
+
// Release the overlap lock BEFORE attempting the Slack post. A slow
|
|
149
|
+
// Slack response must NOT extend the critical section — otherwise the
|
|
150
|
+
// next cron tick can see `locked` even though the job itself finished.
|
|
151
|
+
lock.release();
|
|
152
|
+
lockReleased = true;
|
|
153
|
+
// Best-effort end-of-run Slack notification. Failure NEVER breaks the job
|
|
154
|
+
// — the run already persisted successfully. We log to stderr so cron
|
|
155
|
+
// post-mortems can see why a notify dropped.
|
|
156
|
+
if (job.notifyTarget) {
|
|
157
|
+
try {
|
|
158
|
+
const notify = opts.notify ?? (async (text, target) => {
|
|
159
|
+
const { notify: realNotify } = await import("../gateway/notify.js");
|
|
160
|
+
const r = await realNotify({ text, target });
|
|
161
|
+
return r.ok ? { ok: true } : { ok: false, reason: `${r.code}: ${r.reason}` };
|
|
162
|
+
});
|
|
163
|
+
const summary = `[schedule] ${job.id}: ${result.status} (${result.summary})`;
|
|
164
|
+
const r = await notify(summary, job.notifyTarget);
|
|
165
|
+
if (!r.ok) {
|
|
166
|
+
process.stderr.write(`schedule: notify failed for ${job.id}: ${r.reason ?? "unknown"}\n`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
171
|
+
process.stderr.write(`schedule: notify crashed for ${job.id}: ${msg}\n`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
145
174
|
return result;
|
|
146
175
|
}
|
|
147
176
|
finally {
|
|
148
|
-
|
|
177
|
+
if (!lockReleased)
|
|
178
|
+
lock.release();
|
|
149
179
|
}
|
|
150
180
|
}
|
|
151
181
|
//# sourceMappingURL=runner.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../../src/schedule/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,eAAe,EAAE,SAAS,EAAsB,MAAM,YAAY,CAAC;AACtG,OAAO,EAAE,kBAAkB,EAAoE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../../src/schedule/runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -35,6 +35,13 @@ export interface ScheduleJob {
|
|
|
35
35
|
lastSummary?: string;
|
|
36
36
|
lastLogPath?: string;
|
|
37
37
|
active: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Optional outbound Slack target (`slack:C…`/`slack:G…`/`slack:D…`/`slack:U…`)
|
|
40
|
+
* for end-of-run notification. When set, the runner calls
|
|
41
|
+
* `gateway/notify.notify` with the run summary after each completed run.
|
|
42
|
+
* Notify failures never fail the job — they're logged to stderr only.
|
|
43
|
+
*/
|
|
44
|
+
notifyTarget?: string;
|
|
38
45
|
}
|
|
39
46
|
/** One line in `results/<id>.jsonl`. "Seen" state lives in the cursor, not here. */
|
|
40
47
|
export interface ScheduleRunResult {
|
|
@@ -57,4 +64,6 @@ export interface ScheduleAddOptions {
|
|
|
57
64
|
ttlHours?: number;
|
|
58
65
|
allowAllTools?: boolean;
|
|
59
66
|
dryRun?: boolean;
|
|
67
|
+
/** See ScheduleJob.notifyTarget. */
|
|
68
|
+
notifyTarget?: string;
|
|
60
69
|
}
|