reflectt-node 0.1.7 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/defaults/TEAM-ROLES.yaml +317 -5
- package/defaults/gitignore.template +23 -0
- package/dist/agent-config.d.ts +51 -0
- package/dist/agent-config.d.ts.map +1 -0
- package/dist/agent-config.js +129 -0
- package/dist/agent-config.js.map +1 -0
- package/dist/agent-config.test.d.ts +2 -0
- package/dist/agent-config.test.d.ts.map +1 -0
- package/dist/agent-config.test.js +91 -0
- package/dist/agent-config.test.js.map +1 -0
- package/dist/agent-memories.d.ts +58 -0
- package/dist/agent-memories.d.ts.map +1 -0
- package/dist/agent-memories.js +168 -0
- package/dist/agent-memories.js.map +1 -0
- package/dist/agent-memories.test.d.ts +2 -0
- package/dist/agent-memories.test.d.ts.map +1 -0
- package/dist/agent-memories.test.js +327 -0
- package/dist/agent-memories.test.js.map +1 -0
- package/dist/agent-messaging.d.ts +50 -0
- package/dist/agent-messaging.d.ts.map +1 -0
- package/dist/agent-messaging.js +103 -0
- package/dist/agent-messaging.js.map +1 -0
- package/dist/agent-messaging.test.d.ts +2 -0
- package/dist/agent-messaging.test.d.ts.map +1 -0
- package/dist/agent-messaging.test.js +105 -0
- package/dist/agent-messaging.test.js.map +1 -0
- package/dist/agent-runs.d.ts +158 -0
- package/dist/agent-runs.d.ts.map +1 -0
- package/dist/agent-runs.js +514 -0
- package/dist/agent-runs.js.map +1 -0
- package/dist/agent-runs.test.d.ts +2 -0
- package/dist/agent-runs.test.d.ts.map +1 -0
- package/dist/agent-runs.test.js +386 -0
- package/dist/agent-runs.test.js.map +1 -0
- package/dist/approval-queue.test.d.ts +2 -0
- package/dist/approval-queue.test.d.ts.map +1 -0
- package/dist/approval-queue.test.js +118 -0
- package/dist/approval-queue.test.js.map +1 -0
- package/dist/artifact-store.d.ts +55 -0
- package/dist/artifact-store.d.ts.map +1 -0
- package/dist/artifact-store.js +128 -0
- package/dist/artifact-store.js.map +1 -0
- package/dist/artifact-store.test.d.ts +2 -0
- package/dist/artifact-store.test.d.ts.map +1 -0
- package/dist/artifact-store.test.js +119 -0
- package/dist/artifact-store.test.js.map +1 -0
- package/dist/boardHealthWorker.d.ts +32 -0
- package/dist/boardHealthWorker.d.ts.map +1 -1
- package/dist/boardHealthWorker.js +69 -2
- package/dist/boardHealthWorker.js.map +1 -1
- package/dist/buildInfo.d.ts.map +1 -1
- package/dist/buildInfo.js +47 -10
- package/dist/buildInfo.js.map +1 -1
- package/dist/canvas-input.test.d.ts +2 -0
- package/dist/canvas-input.test.d.ts.map +1 -0
- package/dist/canvas-input.test.js +96 -0
- package/dist/canvas-input.test.js.map +1 -0
- package/dist/canvas-render.test.d.ts +2 -0
- package/dist/canvas-render.test.d.ts.map +1 -0
- package/dist/canvas-render.test.js +95 -0
- package/dist/canvas-render.test.js.map +1 -0
- package/dist/capabilities/browser.d.ts +75 -0
- package/dist/capabilities/browser.d.ts.map +1 -0
- package/dist/capabilities/browser.js +172 -0
- package/dist/capabilities/browser.js.map +1 -0
- package/dist/channels.d.ts +1 -1
- package/dist/chat.d.ts +4 -0
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +6 -2
- package/dist/chat.js.map +1 -1
- package/dist/cli.js +41 -14
- package/dist/cli.js.map +1 -1
- package/dist/cloud.d.ts +2 -0
- package/dist/cloud.d.ts.map +1 -1
- package/dist/cloud.js +151 -64
- package/dist/cloud.js.map +1 -1
- package/dist/continuity-loop.d.ts.map +1 -1
- package/dist/continuity-loop.js +297 -29
- package/dist/continuity-loop.js.map +1 -1
- package/dist/cost-enforcement.d.ts +38 -0
- package/dist/cost-enforcement.d.ts.map +1 -0
- package/dist/cost-enforcement.js +84 -0
- package/dist/cost-enforcement.js.map +1 -0
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +131 -0
- package/dist/db.js.map +1 -1
- package/dist/deploy-monitor.d.ts +18 -0
- package/dist/deploy-monitor.d.ts.map +1 -0
- package/dist/deploy-monitor.js +165 -0
- package/dist/deploy-monitor.js.map +1 -0
- package/dist/e2e-loop-proof.test.d.ts +2 -0
- package/dist/e2e-loop-proof.test.d.ts.map +1 -0
- package/dist/e2e-loop-proof.test.js +104 -0
- package/dist/e2e-loop-proof.test.js.map +1 -0
- package/dist/email-sms-send.test.d.ts +2 -0
- package/dist/email-sms-send.test.d.ts.map +1 -0
- package/dist/email-sms-send.test.js +96 -0
- package/dist/email-sms-send.test.js.map +1 -0
- package/dist/events.d.ts +1 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +2 -0
- package/dist/events.js.map +1 -1
- package/dist/executionSweeper.d.ts +1 -0
- package/dist/executionSweeper.d.ts.map +1 -1
- package/dist/executionSweeper.js +43 -7
- package/dist/executionSweeper.js.map +1 -1
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +17 -3
- package/dist/files.js.map +1 -1
- package/dist/fingerprint.d.ts +30 -0
- package/dist/fingerprint.d.ts.map +1 -0
- package/dist/fingerprint.js +117 -0
- package/dist/fingerprint.js.map +1 -0
- package/dist/github-webhook-attribution.d.ts +38 -0
- package/dist/github-webhook-attribution.d.ts.map +1 -0
- package/dist/github-webhook-attribution.js +123 -0
- package/dist/github-webhook-attribution.js.map +1 -0
- package/dist/github-webhook-chat.d.ts +75 -0
- package/dist/github-webhook-chat.d.ts.map +1 -0
- package/dist/github-webhook-chat.js +108 -0
- package/dist/github-webhook-chat.js.map +1 -0
- package/dist/handoff-state.test.d.ts +2 -0
- package/dist/handoff-state.test.d.ts.map +1 -0
- package/dist/handoff-state.test.js +102 -0
- package/dist/handoff-state.test.js.map +1 -0
- package/dist/health.d.ts +9 -0
- package/dist/health.d.ts.map +1 -1
- package/dist/health.js +18 -0
- package/dist/health.js.map +1 -1
- package/dist/host-error-correlation.d.ts +65 -0
- package/dist/host-error-correlation.d.ts.map +1 -0
- package/dist/host-error-correlation.js +123 -0
- package/dist/host-error-correlation.js.map +1 -0
- package/dist/inbox.d.ts.map +1 -1
- package/dist/inbox.js +4 -0
- package/dist/inbox.js.map +1 -1
- package/dist/index.js +76 -11
- package/dist/index.js.map +1 -1
- package/dist/notificationDedupeGuard.d.ts +4 -0
- package/dist/notificationDedupeGuard.d.ts.map +1 -1
- package/dist/notificationDedupeGuard.js +8 -4
- package/dist/notificationDedupeGuard.js.map +1 -1
- package/dist/presence.d.ts +37 -5
- package/dist/presence.d.ts.map +1 -1
- package/dist/presence.js +127 -16
- package/dist/presence.js.map +1 -1
- package/dist/pulse.d.ts +7 -0
- package/dist/pulse.d.ts.map +1 -1
- package/dist/pulse.js +15 -0
- package/dist/pulse.js.map +1 -1
- package/dist/review-sla.d.ts +9 -0
- package/dist/review-sla.d.ts.map +1 -0
- package/dist/review-sla.js +51 -0
- package/dist/review-sla.js.map +1 -0
- package/dist/review-state.d.ts +9 -0
- package/dist/review-state.d.ts.map +1 -0
- package/dist/review-state.js +17 -0
- package/dist/review-state.js.map +1 -0
- package/dist/routing-enforcement.test.d.ts +2 -0
- package/dist/routing-enforcement.test.d.ts.map +1 -0
- package/dist/routing-enforcement.test.js +86 -0
- package/dist/routing-enforcement.test.js.map +1 -0
- package/dist/run-retention.test.d.ts +2 -0
- package/dist/run-retention.test.d.ts.map +1 -0
- package/dist/run-retention.test.js +57 -0
- package/dist/run-retention.test.js.map +1 -0
- package/dist/run-stream.test.d.ts +2 -0
- package/dist/run-stream.test.d.ts.map +1 -0
- package/dist/run-stream.test.js +70 -0
- package/dist/run-stream.test.js.map +1 -0
- package/dist/schedule.d.ts +60 -0
- package/dist/schedule.d.ts.map +1 -0
- package/dist/schedule.js +176 -0
- package/dist/schedule.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1714 -88
- package/dist/server.js.map +1 -1
- package/dist/suppression-ledger.d.ts.map +1 -1
- package/dist/suppression-ledger.js +12 -3
- package/dist/suppression-ledger.js.map +1 -1
- package/dist/system-loop-state.d.ts +1 -1
- package/dist/system-loop-state.d.ts.map +1 -1
- package/dist/system-loop-state.js +1 -0
- package/dist/system-loop-state.js.map +1 -1
- package/dist/tasks.d.ts +9 -1
- package/dist/tasks.d.ts.map +1 -1
- package/dist/tasks.js +238 -41
- package/dist/tasks.js.map +1 -1
- package/dist/todoHoardingGuard.d.ts +17 -0
- package/dist/todoHoardingGuard.d.ts.map +1 -1
- package/dist/todoHoardingGuard.js +25 -2
- package/dist/todoHoardingGuard.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/usage-tracking.d.ts +26 -0
- package/dist/usage-tracking.d.ts.map +1 -1
- package/dist/usage-tracking.js +91 -4
- package/dist/usage-tracking.js.map +1 -1
- package/dist/webhook-storage.d.ts +50 -0
- package/dist/webhook-storage.d.ts.map +1 -0
- package/dist/webhook-storage.js +102 -0
- package/dist/webhook-storage.js.map +1 -0
- package/dist/webhook-storage.test.d.ts +2 -0
- package/dist/webhook-storage.test.d.ts.map +1 -0
- package/dist/webhook-storage.test.js +86 -0
- package/dist/webhook-storage.test.js.map +1 -0
- package/dist/workflow-templates.d.ts +44 -0
- package/dist/workflow-templates.d.ts.map +1 -0
- package/dist/workflow-templates.js +154 -0
- package/dist/workflow-templates.js.map +1 -0
- package/dist/workflow-templates.test.d.ts +2 -0
- package/dist/workflow-templates.test.d.ts.map +1 -0
- package/dist/workflow-templates.test.js +76 -0
- package/dist/workflow-templates.test.js.map +1 -0
- package/package.json +3 -1
- package/public/dashboard.js +130 -37
- package/public/design-tokens-platform.md +118 -0
- package/public/design-tokens.css +195 -0
- package/public/docs.md +145 -2
package/dist/files.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;CAClB;AAID,QAAA,MAAM,SAAS,QAA+B,CAAA;
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;CAClB;AAID,QAAA,MAAM,SAAS,QAA+B,CAAA;AAK9C,QAAA,MAAM,cAAc,QAA4B,CAAA;AA2BhD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,CAAA;AAuBpC,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,gDAAgD;AAChD,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,YAAY,CA4C3D;AAED,+BAA+B;AAC/B,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAMnD;AAED,kDAAkD;AAClD,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAK9E;AAED,wCAAwC;AACxC,wBAAgB,SAAS,CAAC,IAAI,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG;IAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAuBjJ;AAED,uCAAuC;AACvC,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAe3E;AAED,6DAA6D;AAC7D,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEjD"}
|
package/dist/files.js
CHANGED
|
@@ -5,13 +5,16 @@
|
|
|
5
5
|
// Metadata in SQLite `files` table.
|
|
6
6
|
// 50MB upload limit. Extension allowlist for safety.
|
|
7
7
|
import { randomUUID } from 'node:crypto';
|
|
8
|
-
import { mkdirSync, writeFileSync, readFileSync, unlinkSync, existsSync } from 'node:fs';
|
|
8
|
+
import { mkdirSync, writeFileSync, readFileSync, unlinkSync, existsSync, statSync } from 'node:fs';
|
|
9
9
|
import { join, extname } from 'node:path';
|
|
10
10
|
import { getDb } from './db.js';
|
|
11
11
|
import { REFLECTT_HOME } from './config.js';
|
|
12
12
|
// ── Constants ──
|
|
13
13
|
const FILES_DIR = join(REFLECTT_HOME, 'files');
|
|
14
|
-
|
|
14
|
+
// Configurable upload limit: REFLECTT_MAX_FILE_SIZE_MB env (default 10MB)
|
|
15
|
+
const _envMax = parseInt(process.env.REFLECTT_MAX_FILE_SIZE_MB || '', 10);
|
|
16
|
+
const MAX_SIZE_MB = Number.isFinite(_envMax) && _envMax > 0 ? _envMax : 10;
|
|
17
|
+
const MAX_SIZE_BYTES = MAX_SIZE_MB * 1024 * 1024;
|
|
15
18
|
// Extension → MIME type mapping (allowlist)
|
|
16
19
|
const ALLOWED_EXTENSIONS = {
|
|
17
20
|
'.pdf': 'application/pdf',
|
|
@@ -158,12 +161,23 @@ function rowToMeta(row) {
|
|
|
158
161
|
catch {
|
|
159
162
|
tags = [];
|
|
160
163
|
}
|
|
164
|
+
// Prefer DB value; if missing/zero fall back to actual file size on disk
|
|
165
|
+
let sizeBytes = Number(row.size_bytes);
|
|
166
|
+
if (!sizeBytes || sizeBytes <= 0) {
|
|
167
|
+
const storedPath = String(row.stored_path);
|
|
168
|
+
try {
|
|
169
|
+
sizeBytes = statSync(storedPath).size;
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
sizeBytes = 0;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
161
175
|
return {
|
|
162
176
|
id: String(row.id),
|
|
163
177
|
originalName: String(row.original_name),
|
|
164
178
|
storedPath: String(row.stored_path),
|
|
165
179
|
mimeType: String(row.mime_type),
|
|
166
|
-
sizeBytes
|
|
180
|
+
sizeBytes,
|
|
167
181
|
uploadedBy: String(row.uploaded_by || 'anonymous'),
|
|
168
182
|
tags,
|
|
169
183
|
createdAt: Number(row.created_at) || 0,
|
package/dist/files.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.js","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,kCAAkC;AAClC,EAAE;AACF,2DAA2D;AAC3D,oCAAoC;AACpC,qDAAqD;AAErD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface DeployInfo {
|
|
2
|
+
commit: string;
|
|
3
|
+
version: string;
|
|
4
|
+
deployed_at: number;
|
|
5
|
+
}
|
|
6
|
+
export interface FingerprintEvent {
|
|
7
|
+
event_type: 'error_fingerprint';
|
|
8
|
+
host_id: string;
|
|
9
|
+
deploy: DeployInfo;
|
|
10
|
+
fingerprint: string;
|
|
11
|
+
subsystem: string;
|
|
12
|
+
sample_message: string;
|
|
13
|
+
timestamp: number;
|
|
14
|
+
window_count: number;
|
|
15
|
+
}
|
|
16
|
+
export interface DeployTransitionEvent {
|
|
17
|
+
event_type: 'deploy_transition';
|
|
18
|
+
host_id: string;
|
|
19
|
+
previous_commit: string | null;
|
|
20
|
+
current_commit: string;
|
|
21
|
+
version: string;
|
|
22
|
+
transitioned_at: number;
|
|
23
|
+
}
|
|
24
|
+
export declare function normalizeErrorMessage(raw: string): string;
|
|
25
|
+
export declare function fingerprintError(raw: string): string;
|
|
26
|
+
export declare function recordError(hostId: string, subsystem: string, rawMessage: string): void;
|
|
27
|
+
export declare function getPendingFingerprints(hostId: string, deploy: DeployInfo): FingerprintEvent[];
|
|
28
|
+
export declare function getDeployTransition(hostId: string, deploy: DeployInfo): DeployTransitionEvent | null;
|
|
29
|
+
export declare function getDeployInfo(): DeployInfo;
|
|
30
|
+
//# sourceMappingURL=fingerprint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,mBAAmB,CAAA;IAC/B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,UAAU,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,mBAAmB,CAAA;IAC/B,OAAO,EAAE,MAAM,CAAA;IACf,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,cAAc,EAAE,MAAM,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,eAAe,EAAE,MAAM,CAAA;CACxB;AAkBD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAwBzD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGpD;AAID,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAevF;AAID,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,gBAAgB,EAAE,CAgB7F;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,qBAAqB,GAAG,IAAI,CA0BpG;AAED,wBAAgB,aAAa,IAAI,UAAU,CAQ1C"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) Reflectt AI
|
|
3
|
+
/**
|
|
4
|
+
* Fingerprint Emitter — normalized error fingerprinting + deploy transition tracking
|
|
5
|
+
* Contract: process/TASK-2k0iha2hp-payload-contract.md | Reviewer: @sage
|
|
6
|
+
*/
|
|
7
|
+
import { createHash } from 'node:crypto';
|
|
8
|
+
// execSync removed — use buildInfo instead of shelling out (PR #836 pattern)
|
|
9
|
+
const STARTED_AT = Date.now();
|
|
10
|
+
const WINDOW_MS = 5 * 60 * 1000; // 5 minutes
|
|
11
|
+
// ── Internal state ───────────────────────────────────────────────────────────
|
|
12
|
+
const windows = new Map();
|
|
13
|
+
let previousCommit = null;
|
|
14
|
+
let transitionSent = false;
|
|
15
|
+
// ── Normalization ────────────────────────────────────────────────────────────
|
|
16
|
+
export function normalizeErrorMessage(raw) {
|
|
17
|
+
let s = raw.toLowerCase();
|
|
18
|
+
// Strip absolute paths — keep filename:line only
|
|
19
|
+
s = s.replace(/(?:\/[^\s/:]+)+\/([^\s/]+(?::\d+)?)/g, '$1');
|
|
20
|
+
// Strip unix timestamps (10-13 digit numbers)
|
|
21
|
+
s = s.replace(/\b\d{10,13}\b/g, '');
|
|
22
|
+
// Strip UUIDs
|
|
23
|
+
s = s.replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/g, '');
|
|
24
|
+
// Strip memory addresses
|
|
25
|
+
s = s.replace(/0x[0-9a-f]+/g, '');
|
|
26
|
+
// Strip port numbers
|
|
27
|
+
s = s.replace(/:\d{2,5}\b/g, '');
|
|
28
|
+
// Trim stack trace to top 2 "at " lines
|
|
29
|
+
const lines = s.split('\n');
|
|
30
|
+
let atCount = 0;
|
|
31
|
+
const trimmed = lines.filter(l => {
|
|
32
|
+
if (l.trimStart().startsWith('at ')) {
|
|
33
|
+
atCount++;
|
|
34
|
+
return atCount <= 2;
|
|
35
|
+
}
|
|
36
|
+
return true;
|
|
37
|
+
});
|
|
38
|
+
// Collapse whitespace
|
|
39
|
+
return trimmed.join(' ').replace(/\s+/g, ' ').trim();
|
|
40
|
+
}
|
|
41
|
+
export function fingerprintError(raw) {
|
|
42
|
+
const normalized = normalizeErrorMessage(raw);
|
|
43
|
+
return createHash('sha256').update(normalized).digest('hex').slice(0, 12);
|
|
44
|
+
}
|
|
45
|
+
// ── Recording ─────────────────────────────────────────────────────────────────
|
|
46
|
+
export function recordError(hostId, subsystem, rawMessage) {
|
|
47
|
+
const fp = fingerprintError(rawMessage);
|
|
48
|
+
const now = Date.now();
|
|
49
|
+
const existing = windows.get(fp);
|
|
50
|
+
if (existing && now - existing.firstSeen < WINDOW_MS) {
|
|
51
|
+
existing.window_count++;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
windows.set(fp, {
|
|
55
|
+
fingerprint: fp,
|
|
56
|
+
subsystem,
|
|
57
|
+
sample_message: rawMessage.slice(0, 200),
|
|
58
|
+
firstSeen: now,
|
|
59
|
+
window_count: 1,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// ── Emission ──────────────────────────────────────────────────────────────────
|
|
64
|
+
export function getPendingFingerprints(hostId, deploy) {
|
|
65
|
+
const events = [];
|
|
66
|
+
for (const w of windows.values()) {
|
|
67
|
+
events.push({
|
|
68
|
+
event_type: 'error_fingerprint',
|
|
69
|
+
host_id: hostId,
|
|
70
|
+
deploy,
|
|
71
|
+
fingerprint: w.fingerprint,
|
|
72
|
+
subsystem: w.subsystem,
|
|
73
|
+
sample_message: w.sample_message,
|
|
74
|
+
timestamp: w.firstSeen,
|
|
75
|
+
window_count: w.window_count,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
windows.clear();
|
|
79
|
+
return events;
|
|
80
|
+
}
|
|
81
|
+
export function getDeployTransition(hostId, deploy) {
|
|
82
|
+
if (!transitionSent) {
|
|
83
|
+
transitionSent = true;
|
|
84
|
+
previousCommit = deploy.commit;
|
|
85
|
+
return {
|
|
86
|
+
event_type: 'deploy_transition',
|
|
87
|
+
host_id: hostId,
|
|
88
|
+
previous_commit: null,
|
|
89
|
+
current_commit: deploy.commit,
|
|
90
|
+
version: deploy.version,
|
|
91
|
+
transitioned_at: STARTED_AT,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (previousCommit !== deploy.commit) {
|
|
95
|
+
const prev = previousCommit;
|
|
96
|
+
previousCommit = deploy.commit;
|
|
97
|
+
return {
|
|
98
|
+
event_type: 'deploy_transition',
|
|
99
|
+
host_id: hostId,
|
|
100
|
+
previous_commit: prev,
|
|
101
|
+
current_commit: deploy.commit,
|
|
102
|
+
version: deploy.version,
|
|
103
|
+
transitioned_at: Date.now(),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
export function getDeployInfo() {
|
|
109
|
+
// Use baked buildInfo instead of shelling out to git (fixes ambient-repo bug, same as PR #836)
|
|
110
|
+
const { buildInfo } = require('./buildInfo.js');
|
|
111
|
+
return {
|
|
112
|
+
commit: buildInfo.shortSha || 'unknown',
|
|
113
|
+
version: buildInfo.version || process.env.npm_package_version || '0.0.0',
|
|
114
|
+
deployed_at: STARTED_AT,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=fingerprint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Extract agent name from a branch ref like "link/c8-coverage" or "spark/fix-tests" */
|
|
2
|
+
export declare function extractAgentFromBranch(branchName: string): string | null;
|
|
3
|
+
export interface GitHubWebhookAttribution {
|
|
4
|
+
/** The resolved agent name (e.g. "link") or null if not determinable */
|
|
5
|
+
agent: string | null;
|
|
6
|
+
/** The GitHub username from the event */
|
|
7
|
+
githubUser: string | null;
|
|
8
|
+
/** Whether the GitHub user is a shared account that was remapped */
|
|
9
|
+
remapped: boolean;
|
|
10
|
+
/** Source of the attribution: 'branch', 'fallback', or 'direct' */
|
|
11
|
+
source: 'branch' | 'fallback' | 'direct' | 'none';
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Resolve agent attribution from a GitHub webhook payload.
|
|
15
|
+
*
|
|
16
|
+
* Priority:
|
|
17
|
+
* 1. PR branch name (most reliable — agent/task-xxx convention)
|
|
18
|
+
* 2. Fallback to configured default (kai)
|
|
19
|
+
* 3. null if can't determine
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveWebhookAttribution(payload: Record<string, unknown>): GitHubWebhookAttribution;
|
|
22
|
+
/**
|
|
23
|
+
* Remap shared GitHub @mentions in a pre-formatted message string.
|
|
24
|
+
*
|
|
25
|
+
* Used for cloud-relayed GitHub event messages where the cloud has already
|
|
26
|
+
* formatted the message content (e.g. "@itskaidev\n✅ **PR merged** #828...")
|
|
27
|
+
* but used the raw GitHub sender login instead of the real agent name.
|
|
28
|
+
*
|
|
29
|
+
* Replaces any `@<sharedUsername>` occurrences with `@<fallbackAgent>`.
|
|
30
|
+
* Does NOT perform branch-based lookup (branch info is unavailable at this stage).
|
|
31
|
+
*/
|
|
32
|
+
export declare function remapGitHubMentions(text: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* Enrich a GitHub webhook payload with agent attribution metadata.
|
|
35
|
+
* Adds `_reflectt_attribution` to the payload (non-destructive).
|
|
36
|
+
*/
|
|
37
|
+
export declare function enrichWebhookPayload(payload: Record<string, unknown>): Record<string, unknown>;
|
|
38
|
+
//# sourceMappingURL=github-webhook-attribution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-webhook-attribution.d.ts","sourceRoot":"","sources":["../src/github-webhook-attribution.ts"],"names":[],"mappings":"AAeA,wFAAwF;AACxF,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUxE;AAQD,MAAM,WAAW,wBAAwB;IACvC,wEAAwE;IACxE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,yCAAyC;IACzC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,oEAAoE;IACpE,QAAQ,EAAE,OAAO,CAAA;IACjB,mEAAmE;IACnE,MAAM,EAAE,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,CAAA;CAClD;AAID;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,wBAAwB,CAgCpG;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQxD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAW9F"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) Reflectt AI
|
|
3
|
+
/**
|
|
4
|
+
* GitHub Webhook Agent Attribution
|
|
5
|
+
*
|
|
6
|
+
* Maps GitHub webhook sender usernames (e.g. @itskaidev) to the actual
|
|
7
|
+
* agent who owns the PR, using branch naming convention (agent/...).
|
|
8
|
+
*
|
|
9
|
+
* This enriches webhook payloads with `_reflectt_agent` metadata so
|
|
10
|
+
* downstream consumers know which agent to @mention.
|
|
11
|
+
*/
|
|
12
|
+
import { getAgentRoles } from './assignment.js';
|
|
13
|
+
/** Extract agent name from a branch ref like "link/c8-coverage" or "spark/fix-tests" */
|
|
14
|
+
export function extractAgentFromBranch(branchName) {
|
|
15
|
+
if (!branchName || typeof branchName !== 'string')
|
|
16
|
+
return null;
|
|
17
|
+
// Branch format: <agent>/<anything>
|
|
18
|
+
const slash = branchName.indexOf('/');
|
|
19
|
+
if (slash <= 0)
|
|
20
|
+
return null;
|
|
21
|
+
const candidate = branchName.slice(0, slash).toLowerCase();
|
|
22
|
+
// Validate against known agent names
|
|
23
|
+
const roles = getAgentRoles();
|
|
24
|
+
const match = roles.find(r => r.name.toLowerCase() === candidate);
|
|
25
|
+
return match ? match.name : null;
|
|
26
|
+
}
|
|
27
|
+
/** Known shared GitHub usernames that should be remapped */
|
|
28
|
+
const SHARED_GITHUB_USERNAMES = new Set([
|
|
29
|
+
'itskaidev',
|
|
30
|
+
// Add more shared accounts here if needed
|
|
31
|
+
]);
|
|
32
|
+
const FALLBACK_AGENT = 'kai';
|
|
33
|
+
/**
|
|
34
|
+
* Resolve agent attribution from a GitHub webhook payload.
|
|
35
|
+
*
|
|
36
|
+
* Priority:
|
|
37
|
+
* 1. PR branch name (most reliable — agent/task-xxx convention)
|
|
38
|
+
* 2. Fallback to configured default (kai)
|
|
39
|
+
* 3. null if can't determine
|
|
40
|
+
*/
|
|
41
|
+
export function resolveWebhookAttribution(payload) {
|
|
42
|
+
const sender = extractNestedString(payload, 'sender', 'login');
|
|
43
|
+
const isSharedAccount = sender ? SHARED_GITHUB_USERNAMES.has(sender.toLowerCase()) : false;
|
|
44
|
+
// Try PR branch name first (works for pull_request, pull_request_review, etc.)
|
|
45
|
+
const prBranch = extractNestedString(payload, 'pull_request', 'head', 'ref') ||
|
|
46
|
+
// For push events
|
|
47
|
+
extractBranchFromRef(payload.ref);
|
|
48
|
+
if (prBranch) {
|
|
49
|
+
const agent = extractAgentFromBranch(prBranch);
|
|
50
|
+
if (agent) {
|
|
51
|
+
return { agent, githubUser: sender, remapped: isSharedAccount, source: 'branch' };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// If sender is a shared account and we can't determine from branch, fallback
|
|
55
|
+
if (isSharedAccount) {
|
|
56
|
+
return { agent: FALLBACK_AGENT, githubUser: sender, remapped: true, source: 'fallback' };
|
|
57
|
+
}
|
|
58
|
+
// If sender is a known agent name, use it directly
|
|
59
|
+
if (sender) {
|
|
60
|
+
const roles = getAgentRoles();
|
|
61
|
+
const match = roles.find(r => r.name.toLowerCase() === sender.toLowerCase());
|
|
62
|
+
if (match) {
|
|
63
|
+
return { agent: match.name, githubUser: sender, remapped: false, source: 'direct' };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return { agent: null, githubUser: sender, remapped: false, source: 'none' };
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Remap shared GitHub @mentions in a pre-formatted message string.
|
|
70
|
+
*
|
|
71
|
+
* Used for cloud-relayed GitHub event messages where the cloud has already
|
|
72
|
+
* formatted the message content (e.g. "@itskaidev\n✅ **PR merged** #828...")
|
|
73
|
+
* but used the raw GitHub sender login instead of the real agent name.
|
|
74
|
+
*
|
|
75
|
+
* Replaces any `@<sharedUsername>` occurrences with `@<fallbackAgent>`.
|
|
76
|
+
* Does NOT perform branch-based lookup (branch info is unavailable at this stage).
|
|
77
|
+
*/
|
|
78
|
+
export function remapGitHubMentions(text) {
|
|
79
|
+
if (!text || typeof text !== 'string')
|
|
80
|
+
return text;
|
|
81
|
+
let result = text;
|
|
82
|
+
for (const username of SHARED_GITHUB_USERNAMES) {
|
|
83
|
+
// Match @username at word boundary (avoid partial matches like @itskaidev123)
|
|
84
|
+
result = result.replace(new RegExp(`@${username}\\b`, 'gi'), `@${FALLBACK_AGENT}`);
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Enrich a GitHub webhook payload with agent attribution metadata.
|
|
90
|
+
* Adds `_reflectt_attribution` to the payload (non-destructive).
|
|
91
|
+
*/
|
|
92
|
+
export function enrichWebhookPayload(payload) {
|
|
93
|
+
const attribution = resolveWebhookAttribution(payload);
|
|
94
|
+
return {
|
|
95
|
+
...payload,
|
|
96
|
+
_reflectt_attribution: {
|
|
97
|
+
agent: attribution.agent,
|
|
98
|
+
githubUser: attribution.githubUser,
|
|
99
|
+
remapped: attribution.remapped,
|
|
100
|
+
source: attribution.source,
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
// ─── Helpers ───────────────────────────────────────────────────────
|
|
105
|
+
function extractNestedString(obj, ...keys) {
|
|
106
|
+
let current = obj;
|
|
107
|
+
for (const key of keys) {
|
|
108
|
+
if (!current || typeof current !== 'object')
|
|
109
|
+
return null;
|
|
110
|
+
current = current[key];
|
|
111
|
+
}
|
|
112
|
+
return typeof current === 'string' && current.trim() ? current.trim() : null;
|
|
113
|
+
}
|
|
114
|
+
function extractBranchFromRef(ref) {
|
|
115
|
+
if (!ref || typeof ref !== 'string')
|
|
116
|
+
return null;
|
|
117
|
+
// refs/heads/link/c8-coverage → link/c8-coverage
|
|
118
|
+
const prefix = 'refs/heads/';
|
|
119
|
+
if (ref.startsWith(prefix))
|
|
120
|
+
return ref.slice(prefix.length);
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=github-webhook-attribution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-webhook-attribution.js","sourceRoot":"","sources":["../src/github-webhook-attribution.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,4BAA4B;AAE5B;;;;;;;;GAQG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAE/C,wFAAwF;AACxF,MAAM,UAAU,sBAAsB,CAAC,UAAkB;IACvD,IAAI,CAAC,UAAU,IAAI,OAAO,UAAU,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAA;IAC9D,oCAAoC;IACpC,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACrC,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IAC3B,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,CAAA;IAC1D,qCAAqC;IACrC,MAAM,KAAK,GAAG,aAAa,EAAE,CAAA;IAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,SAAS,CAAC,CAAA;IACjE,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;AAClC,CAAC;AAED,4DAA4D;AAC5D,MAAM,uBAAuB,GAAG,IAAI,GAAG,CAAC;IACtC,WAAW;IACX,0CAA0C;CAC3C,CAAC,CAAA;AAaF,MAAM,cAAc,GAAG,KAAK,CAAA;AAE5B;;;;;;;GAOG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAAgC;IACxE,MAAM,MAAM,GAAG,mBAAmB,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAA;IAC9D,MAAM,eAAe,GAAG,MAAM,CAAC,CAAC,CAAC,uBAAuB,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;IAE1F,+EAA+E;IAC/E,MAAM,QAAQ,GACZ,mBAAmB,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,CAAC;QAC3D,kBAAkB;QAClB,oBAAoB,CAAC,OAAO,CAAC,GAAyB,CAAC,CAAA;IAEzD,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,KAAK,GAAG,sBAAsB,CAAC,QAAQ,CAAC,CAAA;QAC9C,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAA;QACnF,CAAC;IACH,CAAC;IAED,6EAA6E;IAC7E,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,CAAA;IAC1F,CAAC;IAED,mDAAmD;IACnD,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,KAAK,GAAG,aAAa,EAAE,CAAA;QAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,WAAW,EAAE,CAAC,CAAA;QAC5E,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAA;QACrF,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAA;AAC7E,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAA;IAClD,IAAI,MAAM,GAAG,IAAI,CAAA;IACjB,KAAK,MAAM,QAAQ,IAAI,uBAAuB,EAAE,CAAC;QAC/C,8EAA8E;QAC9E,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,IAAI,QAAQ,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,cAAc,EAAE,CAAC,CAAA;IACpF,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAgC;IACnE,MAAM,WAAW,GAAG,yBAAyB,CAAC,OAAO,CAAC,CAAA;IACtD,OAAO;QACL,GAAG,OAAO;QACV,qBAAqB,EAAE;YACrB,KAAK,EAAE,WAAW,CAAC,KAAK;YACxB,UAAU,EAAE,WAAW,CAAC,UAAU;YAClC,QAAQ,EAAE,WAAW,CAAC,QAAQ;YAC9B,MAAM,EAAE,WAAW,CAAC,MAAM;SAC3B;KACF,CAAA;AACH,CAAC;AAED,sEAAsE;AAEtE,SAAS,mBAAmB,CAAC,GAA4B,EAAE,GAAG,IAAc;IAC1E,IAAI,OAAO,GAAY,GAAG,CAAA;IAC1B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAA;QACxD,OAAO,GAAI,OAAmC,CAAC,GAAG,CAAC,CAAA;IACrD,CAAC;IACD,OAAO,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;AAC9E,CAAC;AAED,SAAS,oBAAoB,CAAC,GAAuB;IACnD,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAA;IAChD,iDAAiD;IACjD,MAAM,MAAM,GAAG,aAAa,CAAA;IAC5B,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IAC3D,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
interface ReflecttAttribution {
|
|
2
|
+
agent: string | null;
|
|
3
|
+
githubUser: string | null;
|
|
4
|
+
remapped: boolean;
|
|
5
|
+
source: string;
|
|
6
|
+
}
|
|
7
|
+
interface GitHubEvent extends Record<string, unknown> {
|
|
8
|
+
_reflectt_attribution?: ReflecttAttribution;
|
|
9
|
+
action?: string;
|
|
10
|
+
sender?: {
|
|
11
|
+
login?: string;
|
|
12
|
+
};
|
|
13
|
+
repository?: {
|
|
14
|
+
full_name?: string;
|
|
15
|
+
name?: string;
|
|
16
|
+
};
|
|
17
|
+
pull_request?: {
|
|
18
|
+
number?: number;
|
|
19
|
+
title?: string;
|
|
20
|
+
html_url?: string;
|
|
21
|
+
user?: {
|
|
22
|
+
login?: string;
|
|
23
|
+
};
|
|
24
|
+
merged?: boolean;
|
|
25
|
+
body?: string;
|
|
26
|
+
};
|
|
27
|
+
issue?: {
|
|
28
|
+
number?: number;
|
|
29
|
+
title?: string;
|
|
30
|
+
html_url?: string;
|
|
31
|
+
user?: {
|
|
32
|
+
login?: string;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
comment?: {
|
|
36
|
+
body?: string;
|
|
37
|
+
html_url?: string;
|
|
38
|
+
user?: {
|
|
39
|
+
login?: string;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
review?: {
|
|
43
|
+
state?: string;
|
|
44
|
+
body?: string;
|
|
45
|
+
html_url?: string;
|
|
46
|
+
user?: {
|
|
47
|
+
login?: string;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
ref?: string;
|
|
51
|
+
head_commit?: {
|
|
52
|
+
message?: string;
|
|
53
|
+
author?: {
|
|
54
|
+
username?: string;
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
check_run?: {
|
|
58
|
+
name?: string;
|
|
59
|
+
conclusion?: string;
|
|
60
|
+
html_url?: string;
|
|
61
|
+
};
|
|
62
|
+
workflow_run?: {
|
|
63
|
+
name?: string;
|
|
64
|
+
conclusion?: string;
|
|
65
|
+
html_url?: string;
|
|
66
|
+
head_branch?: string;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Format a GitHub webhook event into a chat message.
|
|
71
|
+
* Returns null if the event should not be posted to chat.
|
|
72
|
+
*/
|
|
73
|
+
export declare function formatGitHubEvent(eventType: string, payload: GitHubEvent): string | null;
|
|
74
|
+
export {};
|
|
75
|
+
//# sourceMappingURL=github-webhook-chat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-webhook-chat.d.ts","sourceRoot":"","sources":["../src/github-webhook-chat.ts"],"names":[],"mappings":"AAeA,UAAU,mBAAmB;IAC3B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,UAAU,WAAY,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACnD,qBAAqB,CAAC,EAAE,mBAAmB,CAAA;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC3B,UAAU,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAClD,YAAY,CAAC,EAAE;QACb,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,IAAI,CAAC,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;QACzB,MAAM,CAAC,EAAE,OAAO,CAAA;QAChB,IAAI,CAAC,EAAE,MAAM,CAAA;KACd,CAAA;IACD,KAAK,CAAC,EAAE;QACN,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,IAAI,CAAC,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAC1B,CAAA;IACD,OAAO,CAAC,EAAE;QACR,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,IAAI,CAAC,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAC1B,CAAA;IACD,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,IAAI,CAAC,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAC1B,CAAA;IACD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE;QACZ,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,MAAM,CAAC,EAAE;YAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAC/B,CAAA;IACD,SAAS,CAAC,EAAE;QACV,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;KAClB,CAAA;IACD,YAAY,CAAC,EAAE;QACb,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,WAAW,CAAC,EAAE,MAAM,CAAA;KACrB,CAAA;CACF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CA0FxF"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) Reflectt AI
|
|
3
|
+
/**
|
|
4
|
+
* GitHub Webhook → Chat Bridge
|
|
5
|
+
*
|
|
6
|
+
* Formats incoming GitHub webhook events as chat messages with
|
|
7
|
+
* agent-remapped mentions and posts them to the 'github' channel.
|
|
8
|
+
* Replaces Discord's native GitHub integration to ensure @mentions
|
|
9
|
+
* resolve to agent names instead of shared GitHub usernames.
|
|
10
|
+
*/
|
|
11
|
+
import { remapGitHubMentions } from './github-webhook-attribution.js';
|
|
12
|
+
/**
|
|
13
|
+
* Format a GitHub webhook event into a chat message.
|
|
14
|
+
* Returns null if the event should not be posted to chat.
|
|
15
|
+
*/
|
|
16
|
+
export function formatGitHubEvent(eventType, payload) {
|
|
17
|
+
const repo = payload.repository?.name || payload.repository?.full_name || 'unknown';
|
|
18
|
+
const rawSender = payload.sender?.login || 'unknown';
|
|
19
|
+
// Prefer branch-resolved agent name from enriched payload attribution.
|
|
20
|
+
// Falls back to remapped GitHub username (e.g. @itskaidev → @kai).
|
|
21
|
+
// This ensures PR events from `link/feature-x` mention @link, not @kai.
|
|
22
|
+
const resolvedAgent = payload._reflectt_attribution?.agent;
|
|
23
|
+
const sender = resolvedAgent ?? remapGitHubMentions(rawSender) ?? rawSender;
|
|
24
|
+
let message = null;
|
|
25
|
+
switch (eventType) {
|
|
26
|
+
case 'pull_request': {
|
|
27
|
+
const pr = payload.pull_request;
|
|
28
|
+
if (!pr)
|
|
29
|
+
break;
|
|
30
|
+
const action = payload.action;
|
|
31
|
+
if (action === 'opened') {
|
|
32
|
+
message = `@${sender} 📝 **PR opened** #${pr.number}: [${pr.title}](${pr.html_url})\nRepo: \`${repo}\``;
|
|
33
|
+
}
|
|
34
|
+
else if (action === 'closed' && pr.merged) {
|
|
35
|
+
message = `@${sender} ✅ **PR merged** #${pr.number}: [${pr.title}](${pr.html_url})\nRepo: \`${repo}\``;
|
|
36
|
+
}
|
|
37
|
+
else if (action === 'closed') {
|
|
38
|
+
message = `@${sender} ❌ **PR closed** #${pr.number}: [${pr.title}](${pr.html_url})\nRepo: \`${repo}\``;
|
|
39
|
+
}
|
|
40
|
+
else if (action === 'review_requested') {
|
|
41
|
+
message = `@${sender} 👀 **Review requested** on #${pr.number}: [${pr.title}](${pr.html_url})\nRepo: \`${repo}\``;
|
|
42
|
+
}
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
case 'pull_request_review': {
|
|
46
|
+
const review = payload.review;
|
|
47
|
+
const pr = payload.pull_request;
|
|
48
|
+
if (!review || !pr)
|
|
49
|
+
break;
|
|
50
|
+
const state = review.state === 'approved' ? '✅ approved' :
|
|
51
|
+
review.state === 'changes_requested' ? '🔄 changes requested' :
|
|
52
|
+
'💬 commented';
|
|
53
|
+
message = `@${sender} ${state} on #${pr.number}: [${pr.title}](${pr.html_url})\nRepo: \`${repo}\``;
|
|
54
|
+
if (review.body)
|
|
55
|
+
message += `\n> ${review.body.slice(0, 200)}`;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
case 'issue_comment':
|
|
59
|
+
case 'pull_request_review_comment': {
|
|
60
|
+
const comment = payload.comment;
|
|
61
|
+
const issue = payload.issue || payload.pull_request;
|
|
62
|
+
if (!comment || !issue)
|
|
63
|
+
break;
|
|
64
|
+
const type = payload.pull_request ? 'PR' : 'Issue';
|
|
65
|
+
message = `@${sender} 💬 **Comment** on ${type} #${issue.number}: [${issue.title}](${issue.html_url})\nRepo: \`${repo}\``;
|
|
66
|
+
if (comment.body)
|
|
67
|
+
message += `\n> ${comment.body.slice(0, 200)}`;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
case 'issues': {
|
|
71
|
+
const issue = payload.issue;
|
|
72
|
+
if (!issue || payload.action !== 'opened')
|
|
73
|
+
break;
|
|
74
|
+
message = `@${sender} 🐛 **Issue opened** #${issue.number}: [${issue.title}](${issue.html_url})\nRepo: \`${repo}\``;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
case 'push': {
|
|
78
|
+
const commit = payload.head_commit;
|
|
79
|
+
if (!commit)
|
|
80
|
+
break;
|
|
81
|
+
const branch = payload.ref?.replace('refs/heads/', '') || 'unknown';
|
|
82
|
+
message = `@${sender} 📦 **Push** to \`${branch}\` on \`${repo}\`\n> ${commit.message?.split('\n')[0]?.slice(0, 100) || 'no message'}`;
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
case 'workflow_run': {
|
|
86
|
+
const run = payload.workflow_run;
|
|
87
|
+
if (!run || payload.action !== 'completed')
|
|
88
|
+
break;
|
|
89
|
+
const icon = run.conclusion === 'success' ? '✅' : run.conclusion === 'failure' ? '❌' : '⚠️';
|
|
90
|
+
message = `${icon} **${run.name}** ${run.conclusion} on \`${run.head_branch}\`\nRepo: \`${repo}\` [View](${run.html_url})`;
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
case 'check_run': {
|
|
94
|
+
const check = payload.check_run;
|
|
95
|
+
if (!check || payload.action !== 'completed' || check.conclusion === 'success')
|
|
96
|
+
break;
|
|
97
|
+
// Only post failed checks
|
|
98
|
+
message = `❌ **Check failed**: ${check.name} — ${check.conclusion}\nRepo: \`${repo}\` [View](${check.html_url})`;
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
default:
|
|
102
|
+
// Don't post unknown event types
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
// Remap GitHub mentions to agent names
|
|
106
|
+
return message ? remapGitHubMentions(message) : null;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=github-webhook-chat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-webhook-chat.js","sourceRoot":"","sources":["../src/github-webhook-chat.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoff-state.test.d.ts","sourceRoot":"","sources":["../src/handoff-state.test.ts"],"names":[],"mappings":""}
|