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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"suppression-ledger.d.ts","sourceRoot":"","sources":["../src/suppression-ledger.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,OAAO,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,OAAO,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,gBAAgB,CAAA;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAA;IACrB,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAClF,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACjF,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,CAAA;CACvB;AAID,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAQ;gBAEZ,QAAQ,CAAC,EAAE,MAAM;IAI7B;;;OAGG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;
|
|
1
|
+
{"version":3,"file":"suppression-ledger.d.ts","sourceRoot":"","sources":["../src/suppression-ledger.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,OAAO,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,OAAO,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,gBAAgB,CAAA;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAA;IACrB,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAClF,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACjF,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,CAAA;CACvB;AAID,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAQ;gBAEZ,QAAQ,CAAC,EAAE,MAAM;IAI7B;;;OAGG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAuB3E;;;;OAIG;IACH,KAAK,CAAC,IAAI,EAAE;QACV,QAAQ,EAAE,MAAM,CAAA;QAChB,OAAO,EAAE,MAAM,CAAA;QACf,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,EAAE,MAAM,CAAA;KAChB,GAAG,sBAAsB;IAyD1B;;OAEG;IACH,QAAQ,IAAI,gBAAgB;IAqC5B;;OAEG;IACH,KAAK,IAAI,MAAM;IAOf;;OAEG;IACH,WAAW,IAAI,MAAM;IAIrB;;OAEG;IACH,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;CAG9B;AAED,eAAO,MAAM,iBAAiB,mBAA0B,CAAA"}
|
|
@@ -16,13 +16,22 @@ export class SuppressionLedger {
|
|
|
16
16
|
* Content is normalized: timestamps, task IDs, and message IDs stripped.
|
|
17
17
|
*/
|
|
18
18
|
computeDedupKey(category, channel, content) {
|
|
19
|
-
|
|
19
|
+
let normalized = content
|
|
20
20
|
.trim()
|
|
21
21
|
.toLowerCase()
|
|
22
22
|
.replace(/\b(msg-|task-|tcomment-|ins-|ref-)\S+/g, '')
|
|
23
23
|
.replace(/\d{13,}/g, '')
|
|
24
|
-
.replace(/\s+/g, ' ')
|
|
25
|
-
|
|
24
|
+
.replace(/\s+/g, ' ');
|
|
25
|
+
// For digest messages, aggressively strip volatile counts so that
|
|
26
|
+
// "32 todo · 2 doing" vs "31 todo · 3 doing" hashes identically.
|
|
27
|
+
// This prevents process restarts from re-emitting the same digest
|
|
28
|
+
// just because task counts shifted by 1-2.
|
|
29
|
+
if (category === 'digest') {
|
|
30
|
+
normalized = normalized
|
|
31
|
+
.replace(/\d+/g, 'N') // normalize all remaining numbers
|
|
32
|
+
.replace(/\bN+\b/g, 'N'); // collapse repeated N
|
|
33
|
+
}
|
|
34
|
+
normalized = normalized.slice(0, 300);
|
|
26
35
|
const raw = `${category}:${channel}:${normalized}`;
|
|
27
36
|
return createHash('sha256').update(raw).digest('hex').substring(0, 20);
|
|
28
37
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"suppression-ledger.js","sourceRoot":"","sources":["../src/suppression-ledger.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iEAAiE;AACjE,EAAE;AACF,mEAAmE;AACnE,iFAAiF;AAEjF,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACnC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAgC/B,MAAM,iBAAiB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA,CAAC,aAAa;AAEtD,MAAM,OAAO,iBAAiB;IACpB,QAAQ,CAAQ;IAExB,YAAY,QAAiB;QAC3B,IAAI,CAAC,QAAQ,GAAG,QAAQ,IAAI,iBAAiB,CAAA;IAC/C,CAAC;IAED;;;OAGG;IACH,eAAe,CAAC,QAAgB,EAAE,OAAe,EAAE,OAAe;QAChE,
|
|
1
|
+
{"version":3,"file":"suppression-ledger.js","sourceRoot":"","sources":["../src/suppression-ledger.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type SystemLoopName = 'idle_nudge' | 'cadence_watchdog' | 'mention_rescue' | 'reflection_pipeline' | 'board_health';
|
|
1
|
+
export type SystemLoopName = 'idle_nudge' | 'cadence_watchdog' | 'mention_rescue' | 'reflection_pipeline' | 'board_health' | 'deploy_monitor';
|
|
2
2
|
export declare function recordSystemLoopTick(name: SystemLoopName, now?: number): void;
|
|
3
3
|
export declare function getSystemLoopTicks(): Record<SystemLoopName, number>;
|
|
4
4
|
//# sourceMappingURL=system-loop-state.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-loop-state.d.ts","sourceRoot":"","sources":["../src/system-loop-state.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,cAAc,GACtB,YAAY,GACZ,kBAAkB,GAClB,gBAAgB,GAChB,qBAAqB,GACrB,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"system-loop-state.d.ts","sourceRoot":"","sources":["../src/system-loop-state.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,cAAc,GACtB,YAAY,GACZ,kBAAkB,GAClB,gBAAgB,GAChB,qBAAqB,GACrB,cAAc,GACd,gBAAgB,CAAA;AAEpB,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,SAAa,GAAG,IAAI,CAWjF;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAsBnE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-loop-state.js","sourceRoot":"","sources":["../src/system-loop-state.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;GAGG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"system-loop-state.js","sourceRoot":"","sources":["../src/system-loop-state.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;GAGG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAU/B,MAAM,UAAU,oBAAoB,CAAC,IAAoB,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IACzE,MAAM,EAAE,GAAG,KAAK,EAAE,CAAA;IAClB,IAAI,CAAC;QACH,EAAE,CAAC,OAAO,CACR;;4EAEsE,CACvE,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,iEAAiE;IACnE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,MAAM,EAAE,GAAG,KAAK,EAAE,CAAA;IAClB,MAAM,GAAG,GAAmC;QAC1C,UAAU,EAAE,CAAC;QACb,gBAAgB,EAAE,CAAC;QACnB,cAAc,EAAE,CAAC;QACjB,mBAAmB,EAAE,CAAC;QACtB,YAAY,EAAE,CAAC;QACf,cAAc,EAAE,CAAC;KAClB,CAAA;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,kDAAkD,CAAC,CAAC,GAAG,EAAmD,CAAA;QAClI,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAmB,CAAA;YAC7C,IAAI,IAAI,IAAI,GAAG;gBAAE,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,CAAA;QAC1D,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;IAED,OAAO,GAAG,CAAA;AACZ,CAAC"}
|
package/dist/tasks.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ declare class TaskManager {
|
|
|
32
32
|
created: number;
|
|
33
33
|
skipped: number;
|
|
34
34
|
}>;
|
|
35
|
+
private appendTaskTombstone;
|
|
35
36
|
/** Write a single task to SQLite + JSONL audit */
|
|
36
37
|
private writeTaskToDb;
|
|
37
38
|
/** Legacy bulk persist — now just writes all tasks from DB to JSONL */
|
|
@@ -73,6 +74,13 @@ declare class TaskManager {
|
|
|
73
74
|
* fields without triggering full validation or history events.
|
|
74
75
|
*/
|
|
75
76
|
patchTaskMetadata(id: string, metadataUpdates: Record<string, unknown>): boolean;
|
|
77
|
+
getTaskDeletionTombstone(inputId: string): {
|
|
78
|
+
taskId: string;
|
|
79
|
+
deletedAt: number;
|
|
80
|
+
deletedBy: string;
|
|
81
|
+
previousStatus: string;
|
|
82
|
+
title: string;
|
|
83
|
+
} | null;
|
|
76
84
|
getTaskHistory(id: string): TaskHistoryEvent[];
|
|
77
85
|
getTaskComments(id: string, options?: {
|
|
78
86
|
includeSuppressed?: boolean;
|
|
@@ -105,7 +113,7 @@ declare class TaskManager {
|
|
|
105
113
|
private parseLaneTransition;
|
|
106
114
|
private applyLaneStateLock;
|
|
107
115
|
updateTask(id: string, updates: Partial<Omit<Task, 'id' | 'createdAt' | 'createdBy'>>): Promise<Task | undefined>;
|
|
108
|
-
deleteTask(id: string): Promise<boolean>;
|
|
116
|
+
deleteTask(id: string, actor?: string): Promise<boolean>;
|
|
109
117
|
subscribe(callback: (task: Task, action: 'created' | 'updated' | 'deleted') => void): () => boolean;
|
|
110
118
|
private notifySubscribers;
|
|
111
119
|
private checkUnblockedTasks;
|
package/dist/tasks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../src/tasks.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../src/tasks.ts"],"names":[],"mappings":"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"}
|
package/dist/tasks.js
CHANGED
|
@@ -9,6 +9,7 @@ import { getDb, importJsonlIfNeeded, safeJsonStringify, safeJsonParse } from './
|
|
|
9
9
|
import { isTestHarnessTask, TEST_TASK_EXCLUDE_SQL } from './test-task-filter.js';
|
|
10
10
|
import { assertDuplicateClosureHasCanonicalRefs } from './duplicateClosureGuard.js';
|
|
11
11
|
import { getAgentAliases } from './assignment.js';
|
|
12
|
+
import { getAgentLane } from './lane-config.js';
|
|
12
13
|
const TASKS_FILE = join(DATA_DIR, 'tasks.jsonl');
|
|
13
14
|
const LEGACY_TASKS_FILE = join(LEGACY_DATA_DIR, 'tasks.jsonl');
|
|
14
15
|
const RECURRING_TASKS_FILE = join(DATA_DIR, 'tasks.recurring.jsonl');
|
|
@@ -25,8 +26,14 @@ function importTasks(db, records) {
|
|
|
25
26
|
tags, metadata, team_id, comment_count, due_at, scheduled_for
|
|
26
27
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
27
28
|
`);
|
|
29
|
+
const del = db.prepare('DELETE FROM tasks WHERE id = ?');
|
|
28
30
|
const insertMany = db.transaction((tasks) => {
|
|
29
31
|
for (const record of tasks) {
|
|
32
|
+
const tombstone = record;
|
|
33
|
+
if (tombstone?.deleted === true && typeof tombstone.id === 'string' && tombstone.id.trim()) {
|
|
34
|
+
del.run(tombstone.id);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
30
37
|
const task = record;
|
|
31
38
|
insert.run(task.id, task.title, task.description ?? null, task.status, task.assignee ?? null, task.reviewer ?? null, safeJsonStringify(task.done_criteria), task.createdBy, task.createdAt, task.updatedAt, task.priority ?? null, safeJsonStringify(task.blocked_by), task.epic_id ?? null, safeJsonStringify(task.tags), safeJsonStringify(task.metadata), task.teamId ?? null, 0, // comment_count will be recalculated when comments are imported
|
|
32
39
|
task.dueAt ?? null, task.scheduledFor ?? null);
|
|
@@ -336,12 +343,18 @@ class TaskManager {
|
|
|
336
343
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
337
344
|
`);
|
|
338
345
|
insert.run(event.id, event.taskId, event.type, event.actor, event.timestamp, safeJsonStringify(event.data));
|
|
346
|
+
}
|
|
347
|
+
catch (err) {
|
|
348
|
+
console.error('[Tasks] Failed to append task history (DB):', err);
|
|
349
|
+
throw err;
|
|
350
|
+
}
|
|
351
|
+
try {
|
|
339
352
|
// Append to JSONL (audit log)
|
|
340
353
|
await fs.mkdir(DATA_DIR, { recursive: true });
|
|
341
354
|
await fs.appendFile(TASK_HISTORY_FILE, `${JSON.stringify(event)}\n`, 'utf-8');
|
|
342
355
|
}
|
|
343
356
|
catch (err) {
|
|
344
|
-
console.error('[Tasks] Failed to append task history:', err);
|
|
357
|
+
console.error('[Tasks] Failed to append task history (JSONL):', err);
|
|
345
358
|
}
|
|
346
359
|
}
|
|
347
360
|
async recordTaskHistoryEvent(taskId, type, actor, data) {
|
|
@@ -356,39 +369,48 @@ class TaskManager {
|
|
|
356
369
|
await this.appendTaskHistory(event);
|
|
357
370
|
}
|
|
358
371
|
async appendTaskComment(comment) {
|
|
372
|
+
const db = getDb();
|
|
373
|
+
// DB writes must be atomic; otherwise callers may observe a "phantom" comment ID
|
|
374
|
+
// that never persisted (breaking review_handoff.comment_id).
|
|
375
|
+
const insert = db.prepare(`
|
|
376
|
+
INSERT INTO task_comments (
|
|
377
|
+
id, task_id, author, content, timestamp,
|
|
378
|
+
category, suppressed, suppressed_reason, suppressed_rule
|
|
379
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
380
|
+
`);
|
|
381
|
+
const updateTask = db.prepare(`
|
|
382
|
+
UPDATE tasks
|
|
383
|
+
SET
|
|
384
|
+
comment_count = (SELECT COUNT(*) FROM task_comments WHERE task_id = ?),
|
|
385
|
+
updated_at = ?
|
|
386
|
+
WHERE id = ?
|
|
387
|
+
`);
|
|
388
|
+
const touchUpdatedAt = db.prepare(`
|
|
389
|
+
UPDATE tasks
|
|
390
|
+
SET updated_at = MAX(updated_at, ?)
|
|
391
|
+
WHERE id = ?
|
|
392
|
+
`);
|
|
393
|
+
try {
|
|
394
|
+
const tx = db.transaction(() => {
|
|
395
|
+
insert.run(comment.id, comment.taskId, comment.author, comment.content, comment.timestamp, comment.category ?? null, comment.suppressed ? 1 : 0, comment.suppressedReason ?? null, comment.suppressedRule ?? null);
|
|
396
|
+
// Comments are material activity and should advance updated_at to avoid autonomy/heartbeat false positives.
|
|
397
|
+
updateTask.run(comment.taskId, comment.timestamp, comment.taskId);
|
|
398
|
+
touchUpdatedAt.run(comment.timestamp, comment.taskId);
|
|
399
|
+
});
|
|
400
|
+
tx();
|
|
401
|
+
}
|
|
402
|
+
catch (err) {
|
|
403
|
+
// Critical: propagate failures so API callers don't record unresolvable comment IDs.
|
|
404
|
+
console.error('[Tasks] Failed to append task comment (DB):', err);
|
|
405
|
+
throw err;
|
|
406
|
+
}
|
|
407
|
+
// Audit log is best-effort; DB is the source of truth.
|
|
359
408
|
try {
|
|
360
|
-
const db = getDb();
|
|
361
|
-
// Write to SQLite (primary)
|
|
362
|
-
const insert = db.prepare(`
|
|
363
|
-
INSERT INTO task_comments (
|
|
364
|
-
id, task_id, author, content, timestamp,
|
|
365
|
-
category, suppressed, suppressed_reason, suppressed_rule
|
|
366
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
367
|
-
`);
|
|
368
|
-
insert.run(comment.id, comment.taskId, comment.author, comment.content, comment.timestamp, comment.category ?? null, comment.suppressed ? 1 : 0, comment.suppressedReason ?? null, comment.suppressedRule ?? null);
|
|
369
|
-
// Update comment count + updated_at for the task.
|
|
370
|
-
// Comments are material activity and should advance updated_at to avoid autonomy/heartbeat false positives.
|
|
371
|
-
const updateTask = db.prepare(`
|
|
372
|
-
UPDATE tasks
|
|
373
|
-
SET
|
|
374
|
-
comment_count = (SELECT COUNT(*) FROM task_comments WHERE task_id = ?),
|
|
375
|
-
updated_at = ?
|
|
376
|
-
WHERE id = ?
|
|
377
|
-
`);
|
|
378
|
-
updateTask.run(comment.taskId, comment.timestamp, comment.taskId);
|
|
379
|
-
// Touch task updated_at so comment activity counts as task activity (autonomy, SLA, sorting)
|
|
380
|
-
const touchUpdatedAt = db.prepare(`
|
|
381
|
-
UPDATE tasks
|
|
382
|
-
SET updated_at = MAX(updated_at, ?)
|
|
383
|
-
WHERE id = ?
|
|
384
|
-
`);
|
|
385
|
-
touchUpdatedAt.run(comment.timestamp, comment.taskId);
|
|
386
|
-
// Append to JSONL (audit log)
|
|
387
409
|
await fs.mkdir(DATA_DIR, { recursive: true });
|
|
388
410
|
await fs.appendFile(TASK_COMMENTS_FILE, `${JSON.stringify(comment)}\n`, 'utf-8');
|
|
389
411
|
}
|
|
390
412
|
catch (err) {
|
|
391
|
-
console.error('[Tasks] Failed to append task comment:', err);
|
|
413
|
+
console.error('[Tasks] Failed to append task comment (JSONL):', err);
|
|
392
414
|
}
|
|
393
415
|
}
|
|
394
416
|
async persistRecurringTasks() {
|
|
@@ -526,18 +548,48 @@ class TaskManager {
|
|
|
526
548
|
}
|
|
527
549
|
return { created, skipped };
|
|
528
550
|
}
|
|
551
|
+
async appendTaskTombstone(task, deletedBy, deletedAt) {
|
|
552
|
+
try {
|
|
553
|
+
await fs.mkdir(DATA_DIR, { recursive: true });
|
|
554
|
+
await fs.appendFile(TASKS_FILE, `${JSON.stringify({
|
|
555
|
+
id: task.id,
|
|
556
|
+
deleted: true,
|
|
557
|
+
deletedAt,
|
|
558
|
+
deletedBy,
|
|
559
|
+
})}\n`, 'utf-8');
|
|
560
|
+
}
|
|
561
|
+
catch (err) {
|
|
562
|
+
console.error('[Tasks] Failed to append task tombstone:', err);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
529
565
|
/** Write a single task to SQLite + JSONL audit */
|
|
530
566
|
writeTaskToDb(task) {
|
|
531
567
|
try {
|
|
532
568
|
const db = getDb();
|
|
533
569
|
const commentCount = this.getTaskCommentCount(task.id);
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
570
|
+
// Use UPDATE for existing tasks to avoid INSERT OR REPLACE which triggers
|
|
571
|
+
// ON DELETE CASCADE on foreign keys (task_comments, task_history), wiping
|
|
572
|
+
// all comments/history for the task. Only INSERT for genuinely new tasks.
|
|
573
|
+
const existing = db.prepare('SELECT 1 FROM tasks WHERE id = ?').get(task.id);
|
|
574
|
+
if (existing) {
|
|
575
|
+
db.prepare(`
|
|
576
|
+
UPDATE tasks SET
|
|
577
|
+
title = ?, description = ?, status = ?, assignee = ?, reviewer = ?,
|
|
578
|
+
done_criteria = ?, created_by = ?, created_at = ?, updated_at = ?,
|
|
579
|
+
priority = ?, blocked_by = ?, epic_id = ?, tags = ?, metadata = ?,
|
|
580
|
+
team_id = ?, comment_count = ?, due_at = ?, scheduled_for = ?
|
|
581
|
+
WHERE id = ?
|
|
582
|
+
`).run(task.title, task.description ?? null, task.status, task.assignee ?? null, task.reviewer ?? null, safeJsonStringify(task.done_criteria), task.createdBy, task.createdAt, task.updatedAt, task.priority ?? null, safeJsonStringify(task.blocked_by), task.epic_id ?? null, safeJsonStringify(task.tags), safeJsonStringify(task.metadata), task.teamId ?? null, commentCount, task.dueAt ?? null, task.scheduledFor ?? null, task.id);
|
|
583
|
+
}
|
|
584
|
+
else {
|
|
585
|
+
db.prepare(`
|
|
586
|
+
INSERT INTO tasks (
|
|
587
|
+
id, title, description, status, assignee, reviewer, done_criteria,
|
|
588
|
+
created_by, created_at, updated_at, priority, blocked_by, epic_id,
|
|
589
|
+
tags, metadata, team_id, comment_count, due_at, scheduled_for
|
|
590
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
591
|
+
`).run(task.id, task.title, task.description ?? null, task.status, task.assignee ?? null, task.reviewer ?? null, safeJsonStringify(task.done_criteria), task.createdBy, task.createdAt, task.updatedAt, task.priority ?? null, safeJsonStringify(task.blocked_by), task.epic_id ?? null, safeJsonStringify(task.tags), safeJsonStringify(task.metadata), task.teamId ?? null, commentCount, task.dueAt ?? null, task.scheduledFor ?? null);
|
|
592
|
+
}
|
|
541
593
|
}
|
|
542
594
|
catch (err) {
|
|
543
595
|
console.error(`[Tasks] Failed to write task ${task.id} to SQLite:`, err);
|
|
@@ -750,6 +802,45 @@ class TaskManager {
|
|
|
750
802
|
this.writeTaskToDb(updated);
|
|
751
803
|
return true;
|
|
752
804
|
}
|
|
805
|
+
getTaskDeletionTombstone(inputId) {
|
|
806
|
+
const db = getDb();
|
|
807
|
+
const raw = String(inputId || '').trim();
|
|
808
|
+
if (!raw)
|
|
809
|
+
return null;
|
|
810
|
+
// Try exact match first, then prefix match against task_history task_ids.
|
|
811
|
+
let taskId = raw;
|
|
812
|
+
const exactRow = db.prepare(`SELECT task_id, data FROM task_history WHERE task_id = ? AND type = 'deleted' ORDER BY timestamp DESC LIMIT 1`).get(raw);
|
|
813
|
+
if (!exactRow) {
|
|
814
|
+
// Prefix match: find task_ids in history that start with the input.
|
|
815
|
+
const prefixRows = db.prepare(`SELECT task_id FROM task_history WHERE task_id LIKE ? AND type = 'deleted' LIMIT 2`).all(raw + '%');
|
|
816
|
+
if (prefixRows.length !== 1)
|
|
817
|
+
return null;
|
|
818
|
+
taskId = prefixRows[0].task_id;
|
|
819
|
+
const prefixRow = db.prepare(`SELECT data FROM task_history WHERE task_id = ? AND type = 'deleted' ORDER BY timestamp DESC LIMIT 1`).get(taskId);
|
|
820
|
+
if (!prefixRow)
|
|
821
|
+
return null;
|
|
822
|
+
const prefixData = safeJsonParse(prefixRow.data);
|
|
823
|
+
if (!prefixData)
|
|
824
|
+
return null;
|
|
825
|
+
return {
|
|
826
|
+
taskId,
|
|
827
|
+
deletedAt: typeof prefixData.deletedAt === 'number' ? prefixData.deletedAt : 0,
|
|
828
|
+
deletedBy: typeof prefixData.deletedBy === 'string' ? prefixData.deletedBy : 'unknown',
|
|
829
|
+
previousStatus: typeof prefixData.previousStatus === 'string' ? prefixData.previousStatus : 'unknown',
|
|
830
|
+
title: typeof prefixData.title === 'string' ? prefixData.title : '',
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
const data = safeJsonParse(exactRow.data);
|
|
834
|
+
if (!data)
|
|
835
|
+
return null;
|
|
836
|
+
return {
|
|
837
|
+
taskId,
|
|
838
|
+
deletedAt: typeof data.deletedAt === 'number' ? data.deletedAt : 0,
|
|
839
|
+
deletedBy: typeof data.deletedBy === 'string' ? data.deletedBy : 'unknown',
|
|
840
|
+
previousStatus: typeof data.previousStatus === 'string' ? data.previousStatus : 'unknown',
|
|
841
|
+
title: typeof data.title === 'string' ? data.title : '',
|
|
842
|
+
};
|
|
843
|
+
}
|
|
753
844
|
getTaskHistory(id) {
|
|
754
845
|
const db = getDb();
|
|
755
846
|
const rows = db.prepare('SELECT * FROM task_history WHERE task_id = ? ORDER BY timestamp ASC').all(id);
|
|
@@ -986,6 +1077,37 @@ class TaskManager {
|
|
|
986
1077
|
return transition;
|
|
987
1078
|
};
|
|
988
1079
|
let transitionEvent;
|
|
1080
|
+
// ── Bounce gate: validating → doing ────────────────────────────────────
|
|
1081
|
+
// A task bouncing from validating back to doing is a signal of rework.
|
|
1082
|
+
// Track bounce_count in metadata. On the 3rd bounce (bounce_count >= 2),
|
|
1083
|
+
// require a documented reason before allowing the regression.
|
|
1084
|
+
if (task.status === 'validating' && nextStatus === 'doing') {
|
|
1085
|
+
const meta = (task.metadata || {});
|
|
1086
|
+
const currentBounce = typeof meta.bounce_count === 'number' ? meta.bounce_count : 0;
|
|
1087
|
+
const newBounceCount = currentBounce + 1;
|
|
1088
|
+
if (currentBounce >= 2) {
|
|
1089
|
+
// 3rd+ bounce: require documented reason
|
|
1090
|
+
if (!transition || typeof transition !== 'object') {
|
|
1091
|
+
throw new Error(`Bounce gate: this task has bounced ${currentBounce} times. ` +
|
|
1092
|
+
`Provide metadata.transition = { type: "bounce_back", reason: "..." } explaining the rework.`);
|
|
1093
|
+
}
|
|
1094
|
+
const bounceReason = transition.reason;
|
|
1095
|
+
if (typeof bounceReason !== 'string' || bounceReason.trim().length === 0) {
|
|
1096
|
+
throw new Error(`Bounce gate: metadata.transition.reason is required when re-opening a task that has bounced ${currentBounce} times.`);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
// Merge bounce_count into metadata, preserving existing task metadata
|
|
1100
|
+
// (task.metadata has eta etc; updates.metadata may have transition or be empty)
|
|
1101
|
+
const existingMeta = {
|
|
1102
|
+
...(task.metadata || {}),
|
|
1103
|
+
...(updates.metadata || {}),
|
|
1104
|
+
};
|
|
1105
|
+
updates.metadata = {
|
|
1106
|
+
...existingMeta,
|
|
1107
|
+
bounce_count: newBounceCount,
|
|
1108
|
+
last_bounce_at: Date.now(),
|
|
1109
|
+
};
|
|
1110
|
+
}
|
|
989
1111
|
if (task.status === 'doing' && nextStatus === 'blocked') {
|
|
990
1112
|
const parsed = requireTransition('pause', ['reason'], 'doing->blocked transition');
|
|
991
1113
|
transitionEvent = {
|
|
@@ -1125,20 +1247,51 @@ class TaskManager {
|
|
|
1125
1247
|
}
|
|
1126
1248
|
return updated;
|
|
1127
1249
|
}
|
|
1128
|
-
async deleteTask(id) {
|
|
1250
|
+
async deleteTask(id, actor = 'system') {
|
|
1129
1251
|
const task = queryTask(id);
|
|
1130
1252
|
if (!task)
|
|
1131
1253
|
return false;
|
|
1132
|
-
|
|
1254
|
+
const deletedAt = Date.now();
|
|
1255
|
+
const event = {
|
|
1256
|
+
id: `thevt-${deletedAt}-${Math.random().toString(36).substr(2, 9)}`,
|
|
1257
|
+
taskId: id,
|
|
1258
|
+
type: 'deleted',
|
|
1259
|
+
actor,
|
|
1260
|
+
timestamp: deletedAt,
|
|
1261
|
+
data: {
|
|
1262
|
+
deletedAt,
|
|
1263
|
+
deletedBy: actor,
|
|
1264
|
+
previousStatus: task.status,
|
|
1265
|
+
title: task.title,
|
|
1266
|
+
},
|
|
1267
|
+
};
|
|
1268
|
+
// Make the live-row delete visible immediately, even if a caller forgets to await deleteTask().
|
|
1269
|
+
// Keep history/comments as audit.
|
|
1133
1270
|
try {
|
|
1134
1271
|
const db = getDb();
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1272
|
+
const insertHistory = db.prepare(`
|
|
1273
|
+
INSERT INTO task_history (id, task_id, type, actor, timestamp, data)
|
|
1274
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
1275
|
+
`);
|
|
1276
|
+
const delTask = db.prepare('DELETE FROM tasks WHERE id = ?');
|
|
1277
|
+
const tx = db.transaction(() => {
|
|
1278
|
+
insertHistory.run(event.id, event.taskId, event.type, event.actor, event.timestamp, safeJsonStringify(event.data));
|
|
1279
|
+
delTask.run(id);
|
|
1280
|
+
});
|
|
1281
|
+
tx();
|
|
1138
1282
|
}
|
|
1139
1283
|
catch (err) {
|
|
1140
1284
|
console.error(`[Tasks] SQLite delete failed for ${id}:`, err);
|
|
1285
|
+
throw err;
|
|
1141
1286
|
}
|
|
1287
|
+
try {
|
|
1288
|
+
await fs.mkdir(DATA_DIR, { recursive: true });
|
|
1289
|
+
await fs.appendFile(TASK_HISTORY_FILE, `${JSON.stringify(event)}\n`, 'utf-8');
|
|
1290
|
+
}
|
|
1291
|
+
catch (err) {
|
|
1292
|
+
console.error('[Tasks] Failed to append delete history (JSONL):', err);
|
|
1293
|
+
}
|
|
1294
|
+
await this.appendTaskTombstone(task, actor, deletedAt);
|
|
1142
1295
|
await this.syncTaskDeleteToCloud(id);
|
|
1143
1296
|
this.notifySubscribers(task, 'deleted');
|
|
1144
1297
|
return true;
|
|
@@ -1237,6 +1390,50 @@ class TaskManager {
|
|
|
1237
1390
|
// so we must treat that sentinel as unassigned for pull-based assignment.
|
|
1238
1391
|
const todoUnassignedRows = db.prepare("SELECT * FROM tasks WHERE status = ? AND (assignee IS NULL OR TRIM(assignee) = '' OR LOWER(assignee) = 'unassigned')").all('todo');
|
|
1239
1392
|
let tasks = todoUnassignedRows.map(rowToTask).filter(t => !isBlocked(t) && filterTestTask(t));
|
|
1393
|
+
// Filter out tasks with a recent handoff to another agent.
|
|
1394
|
+
// If metadata.last_transition.handoff_to exists and points to a different agent,
|
|
1395
|
+
// this task was explicitly routed away and should not be pulled by someone else.
|
|
1396
|
+
if (agent) {
|
|
1397
|
+
const requestingNames = new Set(getAgentAliases(agent));
|
|
1398
|
+
tasks = tasks.filter(t => {
|
|
1399
|
+
const meta = t.metadata;
|
|
1400
|
+
const handoffTo = meta?.last_transition?.handoff_to || meta?.transition?.handoff_to;
|
|
1401
|
+
if (!handoffTo || typeof handoffTo !== 'string')
|
|
1402
|
+
return true; // no handoff — anyone can pull
|
|
1403
|
+
return requestingNames.has(handoffTo.toLowerCase()); // only the handoff target can pull
|
|
1404
|
+
});
|
|
1405
|
+
}
|
|
1406
|
+
// Lane-aware filtering: prevent cross-lane task pulling.
|
|
1407
|
+
// If the requesting agent is in a lane, filter out unassigned tasks that have
|
|
1408
|
+
// a previous assignee in a DIFFERENT lane. This prevents idle agents from
|
|
1409
|
+
// pulling work that belongs to another lane's domain.
|
|
1410
|
+
if (agent) {
|
|
1411
|
+
// getAgentLane imported at top of file
|
|
1412
|
+
const requestingLane = getAgentLane(agent);
|
|
1413
|
+
if (requestingLane) {
|
|
1414
|
+
// Lane-neutral creators: system processes that create tasks for any lane
|
|
1415
|
+
const laneNeutralCreators = new Set(['system', 'insight-bridge', 'insight-task-bridge', 'sweeper', 'ryan']);
|
|
1416
|
+
tasks = tasks.filter(t => {
|
|
1417
|
+
const meta = t.metadata;
|
|
1418
|
+
// Signal 1: explicit previous assignee (strongest — task was actively worked by someone)
|
|
1419
|
+
const prevAssignee = meta?.previous_assignee || meta?.last_transition?.from_assignee;
|
|
1420
|
+
if (prevAssignee && typeof prevAssignee === 'string') {
|
|
1421
|
+
const prevLane = getAgentLane(prevAssignee.toLowerCase());
|
|
1422
|
+
if (prevLane && prevLane.name !== requestingLane.name)
|
|
1423
|
+
return false;
|
|
1424
|
+
}
|
|
1425
|
+
// Signal 2: createdBy agent in another lane (tasks created by an agent
|
|
1426
|
+
// are usually intended for their lane, unless created by system processes)
|
|
1427
|
+
const createdBy = t.createdBy ? t.createdBy.toLowerCase() : null;
|
|
1428
|
+
if (createdBy && !laneNeutralCreators.has(createdBy)) {
|
|
1429
|
+
const creatorLane = getAgentLane(createdBy);
|
|
1430
|
+
if (creatorLane && creatorLane.name !== requestingLane.name)
|
|
1431
|
+
return false;
|
|
1432
|
+
}
|
|
1433
|
+
return true; // no lane conflict — anyone can pull
|
|
1434
|
+
});
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1240
1437
|
if (agent) {
|
|
1241
1438
|
const agentNames = getAgentAliases(agent);
|
|
1242
1439
|
if (agentNames.length > 0) {
|