@asermax/tachikoma 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -0
- package/dist/agent/adapter.d.ts +8 -0
- package/dist/agent/adapter.js +86 -0
- package/dist/agent/adapter.js.map +1 -0
- package/dist/agent/manager.d.ts +35 -0
- package/dist/agent/manager.js +76 -0
- package/dist/agent/manager.js.map +1 -0
- package/dist/agent/models.d.ts +46 -0
- package/dist/agent/models.js +96 -0
- package/dist/agent/models.js.map +1 -0
- package/dist/agent/side-run.d.ts +42 -0
- package/dist/agent/side-run.js +83 -0
- package/dist/agent/side-run.js.map +1 -0
- package/dist/app.d.ts +5 -0
- package/dist/app.js +79 -0
- package/dist/app.js.map +1 -0
- package/dist/channels/types.d.ts +37 -0
- package/dist/channels/types.js +5 -0
- package/dist/channels/types.js.map +1 -0
- package/dist/config/default-template.d.ts +1 -0
- package/dist/config/default-template.js +49 -0
- package/dist/config/default-template.js.map +1 -0
- package/dist/config/load.d.ts +8 -0
- package/dist/config/load.js +28 -0
- package/dist/config/load.js.map +1 -0
- package/dist/config/parse.d.ts +5 -0
- package/dist/config/parse.js +18 -0
- package/dist/config/parse.js.map +1 -0
- package/dist/config/schema.d.ts +29 -0
- package/dist/config/schema.js +35 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/coordinator.d.ts +54 -0
- package/dist/coordinator.js +344 -0
- package/dist/coordinator.js.map +1 -0
- package/dist/db/core-schema.d.ts +250 -0
- package/dist/db/core-schema.js +19 -0
- package/dist/db/core-schema.js.map +1 -0
- package/dist/db/index.d.ts +8 -0
- package/dist/db/index.js +16 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/schema.d.ts +4 -0
- package/dist/db/schema.js +7 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/state.d.ts +10 -0
- package/dist/db/state.js +36 -0
- package/dist/db/state.js.map +1 -0
- package/dist/domain/agent-events.d.ts +26 -0
- package/dist/domain/agent-events.js +2 -0
- package/dist/domain/agent-events.js.map +1 -0
- package/dist/domain/message.d.ts +25 -0
- package/dist/domain/message.js +17 -0
- package/dist/domain/message.js.map +1 -0
- package/dist/events.d.ts +9 -0
- package/dist/events.js +27 -0
- package/dist/events.js.map +1 -0
- package/dist/extensions/api.d.ts +118 -0
- package/dist/extensions/api.js +7 -0
- package/dist/extensions/api.js.map +1 -0
- package/dist/extensions/boundary/detector.d.ts +20 -0
- package/dist/extensions/boundary/detector.js +57 -0
- package/dist/extensions/boundary/detector.js.map +1 -0
- package/dist/extensions/boundary/idle.d.ts +10 -0
- package/dist/extensions/boundary/idle.js +28 -0
- package/dist/extensions/boundary/idle.js.map +1 -0
- package/dist/extensions/boundary/index.d.ts +12 -0
- package/dist/extensions/boundary/index.js +65 -0
- package/dist/extensions/boundary/index.js.map +1 -0
- package/dist/extensions/boundary/summary.d.ts +5 -0
- package/dist/extensions/boundary/summary.js +33 -0
- package/dist/extensions/boundary/summary.js.map +1 -0
- package/dist/extensions/commands/index.d.ts +7 -0
- package/dist/extensions/commands/index.js +21 -0
- package/dist/extensions/commands/index.js.map +1 -0
- package/dist/extensions/context/index.d.ts +7 -0
- package/dist/extensions/context/index.js +65 -0
- package/dist/extensions/context/index.js.map +1 -0
- package/dist/extensions/context/processor.d.ts +27 -0
- package/dist/extensions/context/processor.js +228 -0
- package/dist/extensions/context/processor.js.map +1 -0
- package/dist/extensions/detached-processes/index.d.ts +12 -0
- package/dist/extensions/detached-processes/index.js +51 -0
- package/dist/extensions/detached-processes/index.js.map +1 -0
- package/dist/extensions/detached-processes/limits.d.ts +27 -0
- package/dist/extensions/detached-processes/limits.js +55 -0
- package/dist/extensions/detached-processes/limits.js.map +1 -0
- package/dist/extensions/detached-processes/output.d.ts +2 -0
- package/dist/extensions/detached-processes/output.js +26 -0
- package/dist/extensions/detached-processes/output.js.map +1 -0
- package/dist/extensions/detached-processes/reconcile.d.ts +31 -0
- package/dist/extensions/detached-processes/reconcile.js +71 -0
- package/dist/extensions/detached-processes/reconcile.js.map +1 -0
- package/dist/extensions/detached-processes/repository.d.ts +33 -0
- package/dist/extensions/detached-processes/repository.js +62 -0
- package/dist/extensions/detached-processes/repository.js.map +1 -0
- package/dist/extensions/detached-processes/schema.d.ts +252 -0
- package/dist/extensions/detached-processes/schema.js +23 -0
- package/dist/extensions/detached-processes/schema.js.map +1 -0
- package/dist/extensions/detached-processes/spawn.d.ts +40 -0
- package/dist/extensions/detached-processes/spawn.js +137 -0
- package/dist/extensions/detached-processes/spawn.js.map +1 -0
- package/dist/extensions/detached-processes/tools.d.ts +41 -0
- package/dist/extensions/detached-processes/tools.js +243 -0
- package/dist/extensions/detached-processes/tools.js.map +1 -0
- package/dist/extensions/detached-processes/watcher.d.ts +7 -0
- package/dist/extensions/detached-processes/watcher.js +19 -0
- package/dist/extensions/detached-processes/watcher.js.map +1 -0
- package/dist/extensions/external/index.d.ts +11 -0
- package/dist/extensions/external/index.js +40 -0
- package/dist/extensions/external/index.js.map +1 -0
- package/dist/extensions/external/installs.d.ts +39 -0
- package/dist/extensions/external/installs.js +98 -0
- package/dist/extensions/external/installs.js.map +1 -0
- package/dist/extensions/external/loader.d.ts +19 -0
- package/dist/extensions/external/loader.js +70 -0
- package/dist/extensions/external/loader.js.map +1 -0
- package/dist/extensions/external/tools.d.ts +17 -0
- package/dist/extensions/external/tools.js +112 -0
- package/dist/extensions/external/tools.js.map +1 -0
- package/dist/extensions/git/commit.d.ts +19 -0
- package/dist/extensions/git/commit.js +44 -0
- package/dist/extensions/git/commit.js.map +1 -0
- package/dist/extensions/git/git.d.ts +11 -0
- package/dist/extensions/git/git.js +29 -0
- package/dist/extensions/git/git.js.map +1 -0
- package/dist/extensions/git/hooks.d.ts +10 -0
- package/dist/extensions/git/hooks.js +88 -0
- package/dist/extensions/git/hooks.js.map +1 -0
- package/dist/extensions/git/index.d.ts +11 -0
- package/dist/extensions/git/index.js +28 -0
- package/dist/extensions/git/index.js.map +1 -0
- package/dist/extensions/git/processor.d.ts +13 -0
- package/dist/extensions/git/processor.js +52 -0
- package/dist/extensions/git/processor.js.map +1 -0
- package/dist/extensions/git/sync.d.ts +44 -0
- package/dist/extensions/git/sync.js +189 -0
- package/dist/extensions/git/sync.js.map +1 -0
- package/dist/extensions/git/tools.d.ts +21 -0
- package/dist/extensions/git/tools.js +101 -0
- package/dist/extensions/git/tools.js.map +1 -0
- package/dist/extensions/host.d.ts +31 -0
- package/dist/extensions/host.js +75 -0
- package/dist/extensions/host.js.map +1 -0
- package/dist/extensions/index.d.ts +3 -0
- package/dist/extensions/index.js +32 -0
- package/dist/extensions/index.js.map +1 -0
- package/dist/extensions/memory/archive.d.ts +8 -0
- package/dist/extensions/memory/archive.js +46 -0
- package/dist/extensions/memory/archive.js.map +1 -0
- package/dist/extensions/memory/dates.d.ts +2 -0
- package/dist/extensions/memory/dates.js +7 -0
- package/dist/extensions/memory/dates.js.map +1 -0
- package/dist/extensions/memory/extraction.d.ts +17 -0
- package/dist/extensions/memory/extraction.js +218 -0
- package/dist/extensions/memory/extraction.js.map +1 -0
- package/dist/extensions/memory/index.d.ts +20 -0
- package/dist/extensions/memory/index.js +67 -0
- package/dist/extensions/memory/index.js.map +1 -0
- package/dist/extensions/memory/indexes.d.ts +14 -0
- package/dist/extensions/memory/indexes.js +64 -0
- package/dist/extensions/memory/indexes.js.map +1 -0
- package/dist/extensions/memory/layout.d.ts +20 -0
- package/dist/extensions/memory/layout.js +79 -0
- package/dist/extensions/memory/layout.js.map +1 -0
- package/dist/extensions/memory/maintenance.d.ts +21 -0
- package/dist/extensions/memory/maintenance.js +357 -0
- package/dist/extensions/memory/maintenance.js.map +1 -0
- package/dist/extensions/memory/prompts.d.ts +8 -0
- package/dist/extensions/memory/prompts.js +125 -0
- package/dist/extensions/memory/prompts.js.map +1 -0
- package/dist/extensions/memory/transcript.d.ts +18 -0
- package/dist/extensions/memory/transcript.js +79 -0
- package/dist/extensions/memory/transcript.js.map +1 -0
- package/dist/extensions/notifications/format.d.ts +5 -0
- package/dist/extensions/notifications/format.js +17 -0
- package/dist/extensions/notifications/format.js.map +1 -0
- package/dist/extensions/notifications/index.d.ts +13 -0
- package/dist/extensions/notifications/index.js +29 -0
- package/dist/extensions/notifications/index.js.map +1 -0
- package/dist/extensions/notifications/payload.d.ts +22 -0
- package/dist/extensions/notifications/payload.js +29 -0
- package/dist/extensions/notifications/payload.js.map +1 -0
- package/dist/extensions/notifications/router.d.ts +29 -0
- package/dist/extensions/notifications/router.js +55 -0
- package/dist/extensions/notifications/router.js.map +1 -0
- package/dist/extensions/notifications/tools.d.ts +12 -0
- package/dist/extensions/notifications/tools.js +41 -0
- package/dist/extensions/notifications/tools.js.map +1 -0
- package/dist/extensions/projects/context-provider.d.ts +9 -0
- package/dist/extensions/projects/context-provider.js +37 -0
- package/dist/extensions/projects/context-provider.js.map +1 -0
- package/dist/extensions/projects/git.d.ts +28 -0
- package/dist/extensions/projects/git.js +91 -0
- package/dist/extensions/projects/git.js.map +1 -0
- package/dist/extensions/projects/hooks.d.ts +7 -0
- package/dist/extensions/projects/hooks.js +42 -0
- package/dist/extensions/projects/hooks.js.map +1 -0
- package/dist/extensions/projects/index.d.ts +11 -0
- package/dist/extensions/projects/index.js +30 -0
- package/dist/extensions/projects/index.js.map +1 -0
- package/dist/extensions/projects/processor.d.ts +13 -0
- package/dist/extensions/projects/processor.js +63 -0
- package/dist/extensions/projects/processor.js.map +1 -0
- package/dist/extensions/projects/tools.d.ts +21 -0
- package/dist/extensions/projects/tools.js +118 -0
- package/dist/extensions/projects/tools.js.map +1 -0
- package/dist/extensions/registrations.d.ts +21 -0
- package/dist/extensions/registrations.js +12 -0
- package/dist/extensions/registrations.js.map +1 -0
- package/dist/extensions/repl/index.d.ts +2 -0
- package/dist/extensions/repl/index.js +85 -0
- package/dist/extensions/repl/index.js.map +1 -0
- package/dist/extensions/skills/agents.d.ts +17 -0
- package/dist/extensions/skills/agents.js +77 -0
- package/dist/extensions/skills/agents.js.map +1 -0
- package/dist/extensions/skills/delegate.d.ts +22 -0
- package/dist/extensions/skills/delegate.js +54 -0
- package/dist/extensions/skills/delegate.js.map +1 -0
- package/dist/extensions/skills/index.d.ts +11 -0
- package/dist/extensions/skills/index.js +43 -0
- package/dist/extensions/skills/index.js.map +1 -0
- package/dist/extensions/skills/reload.d.ts +8 -0
- package/dist/extensions/skills/reload.js +38 -0
- package/dist/extensions/skills/reload.js.map +1 -0
- package/dist/extensions/tasks/executor.d.ts +43 -0
- package/dist/extensions/tasks/executor.js +179 -0
- package/dist/extensions/tasks/executor.js.map +1 -0
- package/dist/extensions/tasks/expiration.d.ts +12 -0
- package/dist/extensions/tasks/expiration.js +17 -0
- package/dist/extensions/tasks/expiration.js.map +1 -0
- package/dist/extensions/tasks/generation.d.ts +14 -0
- package/dist/extensions/tasks/generation.js +70 -0
- package/dist/extensions/tasks/generation.js.map +1 -0
- package/dist/extensions/tasks/index.d.ts +14 -0
- package/dist/extensions/tasks/index.js +75 -0
- package/dist/extensions/tasks/index.js.map +1 -0
- package/dist/extensions/tasks/repository.d.ts +53 -0
- package/dist/extensions/tasks/repository.js +147 -0
- package/dist/extensions/tasks/repository.js.map +1 -0
- package/dist/extensions/tasks/schedule.d.ts +13 -0
- package/dist/extensions/tasks/schedule.js +32 -0
- package/dist/extensions/tasks/schedule.js.map +1 -0
- package/dist/extensions/tasks/schema.d.ts +423 -0
- package/dist/extensions/tasks/schema.js +45 -0
- package/dist/extensions/tasks/schema.js.map +1 -0
- package/dist/extensions/tasks/session-delivery.d.ts +18 -0
- package/dist/extensions/tasks/session-delivery.js +39 -0
- package/dist/extensions/tasks/session-delivery.js.map +1 -0
- package/dist/extensions/tasks/tools.d.ts +38 -0
- package/dist/extensions/tasks/tools.js +181 -0
- package/dist/extensions/tasks/tools.js.map +1 -0
- package/dist/extensions/telegram/buttons.d.ts +14 -0
- package/dist/extensions/telegram/buttons.js +49 -0
- package/dist/extensions/telegram/buttons.js.map +1 -0
- package/dist/extensions/telegram/channel.d.ts +39 -0
- package/dist/extensions/telegram/channel.js +201 -0
- package/dist/extensions/telegram/channel.js.map +1 -0
- package/dist/extensions/telegram/chunking.d.ts +7 -0
- package/dist/extensions/telegram/chunking.js +67 -0
- package/dist/extensions/telegram/chunking.js.map +1 -0
- package/dist/extensions/telegram/inbound.d.ts +7 -0
- package/dist/extensions/telegram/inbound.js +29 -0
- package/dist/extensions/telegram/inbound.js.map +1 -0
- package/dist/extensions/telegram/index.d.ts +13 -0
- package/dist/extensions/telegram/index.js +67 -0
- package/dist/extensions/telegram/index.js.map +1 -0
- package/dist/extensions/telegram/media.d.ts +39 -0
- package/dist/extensions/telegram/media.js +223 -0
- package/dist/extensions/telegram/media.js.map +1 -0
- package/dist/extensions/telegram/mutex.d.ts +9 -0
- package/dist/extensions/telegram/mutex.js +14 -0
- package/dist/extensions/telegram/mutex.js.map +1 -0
- package/dist/extensions/telegram/sending.d.ts +48 -0
- package/dist/extensions/telegram/sending.js +119 -0
- package/dist/extensions/telegram/sending.js.map +1 -0
- package/dist/extensions/telegram/streaming.d.ts +46 -0
- package/dist/extensions/telegram/streaming.js +140 -0
- package/dist/extensions/telegram/streaming.js.map +1 -0
- package/dist/extensions/telegram/tools.d.ts +80 -0
- package/dist/extensions/telegram/tools.js +232 -0
- package/dist/extensions/telegram/tools.js.map +1 -0
- package/dist/extensions/workflows/cleanup.d.ts +10 -0
- package/dist/extensions/workflows/cleanup.js +38 -0
- package/dist/extensions/workflows/cleanup.js.map +1 -0
- package/dist/extensions/workflows/index.d.ts +11 -0
- package/dist/extensions/workflows/index.js +42 -0
- package/dist/extensions/workflows/index.js.map +1 -0
- package/dist/extensions/workflows/loader.d.ts +27 -0
- package/dist/extensions/workflows/loader.js +90 -0
- package/dist/extensions/workflows/loader.js.map +1 -0
- package/dist/extensions/workflows/model.d.ts +19 -0
- package/dist/extensions/workflows/model.js +7 -0
- package/dist/extensions/workflows/model.js.map +1 -0
- package/dist/extensions/workflows/repository.d.ts +24 -0
- package/dist/extensions/workflows/repository.js +61 -0
- package/dist/extensions/workflows/repository.js.map +1 -0
- package/dist/extensions/workflows/schema.d.ts +193 -0
- package/dist/extensions/workflows/schema.js +20 -0
- package/dist/extensions/workflows/schema.js.map +1 -0
- package/dist/extensions/workflows/tools.d.ts +27 -0
- package/dist/extensions/workflows/tools.js +285 -0
- package/dist/extensions/workflows/tools.js.map +1 -0
- package/dist/log.d.ts +8 -0
- package/dist/log.js +15 -0
- package/dist/log.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +27 -0
- package/dist/main.js.map +1 -0
- package/dist/migration/ask.d.ts +8 -0
- package/dist/migration/ask.js +24 -0
- package/dist/migration/ask.js.map +1 -0
- package/dist/migration/config.d.ts +10 -0
- package/dist/migration/config.js +122 -0
- package/dist/migration/config.js.map +1 -0
- package/dist/migration/context.d.ts +3 -0
- package/dist/migration/context.js +24 -0
- package/dist/migration/context.js.map +1 -0
- package/dist/migration/database.d.ts +8 -0
- package/dist/migration/database.js +51 -0
- package/dist/migration/database.js.map +1 -0
- package/dist/migration/fs.d.ts +1 -0
- package/dist/migration/fs.js +11 -0
- package/dist/migration/fs.js.map +1 -0
- package/dist/migration/index.d.ts +11 -0
- package/dist/migration/index.js +28 -0
- package/dist/migration/index.js.map +1 -0
- package/dist/migration/skills.d.ts +19 -0
- package/dist/migration/skills.js +77 -0
- package/dist/migration/skills.js.map +1 -0
- package/dist/scheduler.d.ts +17 -0
- package/dist/scheduler.js +53 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/sessions/registry.d.ts +15 -0
- package/dist/sessions/registry.js +42 -0
- package/dist/sessions/registry.js.map +1 -0
- package/dist/workspace.d.ts +13 -0
- package/dist/workspace.js +32 -0
- package/dist/workspace.js.map +1 -0
- package/drizzle/0000_init.sql +19 -0
- package/drizzle/0001_extensions.sql +63 -0
- package/drizzle/meta/0000_snapshot.json +134 -0
- package/drizzle/meta/0001_snapshot.json +526 -0
- package/drizzle/meta/_journal.json +20 -0
- package/package.json +63 -0
- package/skills/skill-authoring/SKILL.md +168 -0
- package/skills/workflow-authoring/SKILL.md +251 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../../src/extensions/notifications/format.ts"],"names":[],"mappings":"AAEA,MAAM,eAAe,GAAG,CAAC,IAAU,EAAU,EAAE,CAC7C,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC;AAE7D,6DAA6D;AAC7D,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,OAAsB,EAAE,GAAS,EAAU,EAAE;IAC9E,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;IAE1F,OAAO,iCAAiC,OAAO,CAAC,MAAM,WAAW,eAAe,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;AACrG,CAAC,CAAC;AAEF,uDAAuD;AACvD,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAsB,EAAE,GAAS,EAAU,EAAE;IACxE,MAAM,KAAK,GAAG,CAAC,uCAAuC,eAAe,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IAElF,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC5B,KAAK,CAAC,IAAI,CAAC,UAAU,KAAK,GAAG,CAAC,KAAK,IAAI,CAAC,QAAQ,aAAa,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC;QAC/E,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3E,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type { NotifyPayload, Severity } from "./payload.ts";
|
|
2
|
+
interface NotificationsConfig {
|
|
3
|
+
flushWindowSeconds: number;
|
|
4
|
+
maxHoldSeconds: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Notification delivery: routes `"notify"` app events to the user by severity —
|
|
8
|
+
* urgent immediately, the rest idle-gated with a max hold, batched into a digest
|
|
9
|
+
* when several accumulate. Also exposes a notify_user tool so the agent itself
|
|
10
|
+
* can emit notifications.
|
|
11
|
+
*/
|
|
12
|
+
declare const _default: import("../api.ts").TachikomaExtension<NotificationsConfig>;
|
|
13
|
+
export default _default;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import { defineExtension } from "../api.js";
|
|
3
|
+
import { NOTIFY_EVENT } from "./payload.js";
|
|
4
|
+
import { NotificationRouter } from "./router.js";
|
|
5
|
+
import { createNotifyToolFactory } from "./tools.js";
|
|
6
|
+
/**
|
|
7
|
+
* Notification delivery: routes `"notify"` app events to the user by severity —
|
|
8
|
+
* urgent immediately, the rest idle-gated with a max hold, batched into a digest
|
|
9
|
+
* when several accumulate. Also exposes a notify_user tool so the agent itself
|
|
10
|
+
* can emit notifications.
|
|
11
|
+
*/
|
|
12
|
+
export default defineExtension({
|
|
13
|
+
name: "notifications",
|
|
14
|
+
configSchema: Type.Object({
|
|
15
|
+
flushWindowSeconds: Type.Number({ default: 30 }),
|
|
16
|
+
maxHoldSeconds: Type.Number({ default: 900 }),
|
|
17
|
+
}),
|
|
18
|
+
setup(app) {
|
|
19
|
+
const router = new NotificationRouter({
|
|
20
|
+
deliver: (delivery) => app.channels.deliver(delivery),
|
|
21
|
+
flushWindowSeconds: app.extensionConfig.flushWindowSeconds,
|
|
22
|
+
maxHoldSeconds: app.extensionConfig.maxHoldSeconds,
|
|
23
|
+
log: app.log,
|
|
24
|
+
});
|
|
25
|
+
app.events.on(NOTIFY_EVENT, (payload) => router.handle(payload));
|
|
26
|
+
app.agent.use(createNotifyToolFactory((event, payload) => app.events.emit(event, payload)));
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/notifications/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AASrD;;;;;GAKG;AACH,eAAe,eAAe,CAAsB;IAClD,IAAI,EAAE,eAAe;IAErB,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC;QACxB,kBAAkB,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QAChD,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;KAC9C,CAAC;IAEF,KAAK,CAAC,GAAG;QACP,MAAM,MAAM,GAAG,IAAI,kBAAkB,CAAC;YACpC,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC;YACrD,kBAAkB,EAAE,GAAG,CAAC,eAAe,CAAC,kBAAkB;YAC1D,cAAc,EAAE,GAAG,CAAC,eAAe,CAAC,cAAc;YAClD,GAAG,EAAE,GAAG,CAAC,GAAG;SACb,CAAC,CAAC;QAEH,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QAEjE,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAC9F,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** App event channel for user-facing notifications from any extension. */
|
|
2
|
+
export declare const NOTIFY_EVENT = "notify";
|
|
3
|
+
export declare const SEVERITIES: {
|
|
4
|
+
readonly info: "info";
|
|
5
|
+
readonly warning: "warning";
|
|
6
|
+
readonly urgent: "urgent";
|
|
7
|
+
};
|
|
8
|
+
export type Severity = keyof typeof SEVERITIES;
|
|
9
|
+
export interface NotifyPayload {
|
|
10
|
+
title?: string;
|
|
11
|
+
text: string;
|
|
12
|
+
severity: Severity;
|
|
13
|
+
source: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Parse an arbitrary `"notify"` event payload into a NotifyPayload.
|
|
17
|
+
*
|
|
18
|
+
* Requires a non-empty `text` string; payloads without one are not notifications
|
|
19
|
+
* and return null. Missing or unknown severity downgrades to "info", missing
|
|
20
|
+
* source becomes "unknown" — cross-extension signals stay best-effort.
|
|
21
|
+
*/
|
|
22
|
+
export declare const parseNotifyPayload: (payload: unknown) => NotifyPayload | null;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** App event channel for user-facing notifications from any extension. */
|
|
2
|
+
export const NOTIFY_EVENT = "notify";
|
|
3
|
+
export const SEVERITIES = {
|
|
4
|
+
info: "info",
|
|
5
|
+
warning: "warning",
|
|
6
|
+
urgent: "urgent",
|
|
7
|
+
};
|
|
8
|
+
const isSeverity = (value) => typeof value === "string" && value in SEVERITIES;
|
|
9
|
+
/**
|
|
10
|
+
* Parse an arbitrary `"notify"` event payload into a NotifyPayload.
|
|
11
|
+
*
|
|
12
|
+
* Requires a non-empty `text` string; payloads without one are not notifications
|
|
13
|
+
* and return null. Missing or unknown severity downgrades to "info", missing
|
|
14
|
+
* source becomes "unknown" — cross-extension signals stay best-effort.
|
|
15
|
+
*/
|
|
16
|
+
export const parseNotifyPayload = (payload) => {
|
|
17
|
+
if (payload == null || typeof payload !== "object")
|
|
18
|
+
return null;
|
|
19
|
+
const candidate = payload;
|
|
20
|
+
if (typeof candidate.text !== "string" || candidate.text.trim() === "")
|
|
21
|
+
return null;
|
|
22
|
+
return {
|
|
23
|
+
title: typeof candidate.title === "string" ? candidate.title : undefined,
|
|
24
|
+
text: candidate.text,
|
|
25
|
+
severity: isSeverity(candidate.severity) ? candidate.severity : SEVERITIES.info,
|
|
26
|
+
source: typeof candidate.source === "string" ? candidate.source : "unknown",
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=payload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payload.js","sourceRoot":"","sources":["../../../src/extensions/notifications/payload.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,MAAM,CAAC,MAAM,YAAY,GAAG,QAAQ,CAAC;AAErC,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,QAAQ;CACR,CAAC;AAWX,MAAM,UAAU,GAAG,CAAC,KAAc,EAAqB,EAAE,CACvD,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,UAAU,CAAC;AAEnD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,OAAgB,EAAwB,EAAE;IAC3E,IAAI,OAAO,IAAI,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAEhE,MAAM,SAAS,GAAG,OAAkC,CAAC;IAErD,IAAI,OAAO,SAAS,CAAC,IAAI,KAAK,QAAQ,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAEpF,OAAO;QACL,KAAK,EAAE,OAAO,SAAS,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;QACxE,IAAI,EAAE,SAAS,CAAC,IAAI;QACpB,QAAQ,EAAE,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI;QAC/E,MAAM,EAAE,OAAO,SAAS,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;KAC5E,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Delivery } from "../../channels/types.ts";
|
|
2
|
+
import type { Logger } from "../../log.ts";
|
|
3
|
+
export interface RouterOptions {
|
|
4
|
+
deliver: (delivery: Delivery) => void;
|
|
5
|
+
/** How long non-urgent notices accumulate before flushing as one block. */
|
|
6
|
+
flushWindowSeconds: number;
|
|
7
|
+
/** Forwarded to the idle gate so held notices are force-delivered eventually. */
|
|
8
|
+
maxHoldSeconds: number;
|
|
9
|
+
log: Logger;
|
|
10
|
+
now?: () => Date;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Severity router for `"notify"` events: urgent notices bypass gating and deliver
|
|
14
|
+
* immediately; everything else accumulates over a short flush window and goes out
|
|
15
|
+
* idle-gated — as a single notification or, when several piled up, as one digest.
|
|
16
|
+
*/
|
|
17
|
+
export declare class NotificationRouter {
|
|
18
|
+
private readonly deliver;
|
|
19
|
+
private readonly flushWindowSeconds;
|
|
20
|
+
private readonly maxHoldSeconds;
|
|
21
|
+
private readonly log;
|
|
22
|
+
private readonly now;
|
|
23
|
+
private pending;
|
|
24
|
+
private timer;
|
|
25
|
+
constructor({ deliver, flushWindowSeconds, maxHoldSeconds, log, now }: RouterOptions);
|
|
26
|
+
handle(payload: unknown): void;
|
|
27
|
+
/** Deliver everything accumulated so far as one idle-gated block. */
|
|
28
|
+
flush(): void;
|
|
29
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { formatDigest, formatNotification } from "./format.js";
|
|
2
|
+
import { parseNotifyPayload, SEVERITIES } from "./payload.js";
|
|
3
|
+
/**
|
|
4
|
+
* Severity router for `"notify"` events: urgent notices bypass gating and deliver
|
|
5
|
+
* immediately; everything else accumulates over a short flush window and goes out
|
|
6
|
+
* idle-gated — as a single notification or, when several piled up, as one digest.
|
|
7
|
+
*/
|
|
8
|
+
export class NotificationRouter {
|
|
9
|
+
deliver;
|
|
10
|
+
flushWindowSeconds;
|
|
11
|
+
maxHoldSeconds;
|
|
12
|
+
log;
|
|
13
|
+
now;
|
|
14
|
+
pending = [];
|
|
15
|
+
timer = null;
|
|
16
|
+
constructor({ deliver, flushWindowSeconds, maxHoldSeconds, log, now }) {
|
|
17
|
+
this.deliver = deliver;
|
|
18
|
+
this.flushWindowSeconds = flushWindowSeconds;
|
|
19
|
+
this.maxHoldSeconds = maxHoldSeconds;
|
|
20
|
+
this.log = log;
|
|
21
|
+
this.now = now ?? (() => new Date());
|
|
22
|
+
}
|
|
23
|
+
handle(payload) {
|
|
24
|
+
const parsed = parseNotifyPayload(payload);
|
|
25
|
+
if (parsed == null) {
|
|
26
|
+
// Other extensions emit non-notification signals on this event (e.g. task
|
|
27
|
+
// status objects) — those are not for the user, so skip them quietly.
|
|
28
|
+
this.log.debug({ payload }, "ignoring notify event without notification text");
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (parsed.severity === SEVERITIES.urgent) {
|
|
32
|
+
this.deliver({ text: formatNotification(parsed, this.now()), gate: "immediate" });
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
this.pending.push(parsed);
|
|
36
|
+
if (this.timer == null) {
|
|
37
|
+
this.timer = setTimeout(() => this.flush(), this.flushWindowSeconds * 1000);
|
|
38
|
+
this.timer.unref();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Deliver everything accumulated so far as one idle-gated block. */
|
|
42
|
+
flush() {
|
|
43
|
+
if (this.timer != null)
|
|
44
|
+
clearTimeout(this.timer);
|
|
45
|
+
this.timer = null;
|
|
46
|
+
const items = this.pending;
|
|
47
|
+
this.pending = [];
|
|
48
|
+
const [single] = items;
|
|
49
|
+
if (single == null)
|
|
50
|
+
return;
|
|
51
|
+
const text = items.length === 1 ? formatNotification(single, this.now()) : formatDigest(items, this.now());
|
|
52
|
+
this.deliver({ text, gate: "idle", maxHoldSeconds: this.maxHoldSeconds });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../../src/extensions/notifications/router.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAsB,kBAAkB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAYlF;;;;GAIG;AACH,MAAM,OAAO,kBAAkB;IACZ,OAAO,CAA+B;IACtC,kBAAkB,CAAS;IAC3B,cAAc,CAAS;IACvB,GAAG,CAAS;IACZ,GAAG,CAAa;IAEzB,OAAO,GAAoB,EAAE,CAAC;IAC9B,KAAK,GAA0B,IAAI,CAAC;IAE5C,YAAY,EAAE,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG,EAAiB;QAClF,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,kBAAkB,GAAG,kBAAkB,CAAC;QAC7C,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,CAAC,OAAgB;QACrB,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAE3C,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;YACnB,0EAA0E;YAC1E,sEAAsE;YACtE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,EAAE,iDAAiD,CAAC,CAAC;YAC/E,OAAO;QACT,CAAC;QAED,IAAI,MAAM,CAAC,QAAQ,KAAK,UAAU,CAAC,MAAM,EAAE,CAAC;YAC1C,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;YAClF,OAAO;QACT,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE1B,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC;YAC5E,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACrB,CAAC;IACH,CAAC;IAED,qEAAqE;IACrE,KAAK;QACH,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI;YAAE,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAElB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC;QAC3B,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QAElB,MAAM,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC;QAEvB,IAAI,MAAM,IAAI,IAAI;YAAE,OAAO;QAE3B,MAAM,IAAI,GACR,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAEhG,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;IAC5E,CAAC;CACF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ExtensionFactory } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { type Static, Type } from "typebox";
|
|
3
|
+
import { type NotifyPayload } from "./payload.ts";
|
|
4
|
+
export type NotifyEmitter = (event: string, payload: NotifyPayload) => void;
|
|
5
|
+
export declare const NotifyUserParams: Type.TObject<{
|
|
6
|
+
text: Type.TString;
|
|
7
|
+
title: Type.TOptional<Type.TString>;
|
|
8
|
+
severity: Type.TOptional<Type.TUnsafe<"info" | "warning" | "urgent">>;
|
|
9
|
+
}>;
|
|
10
|
+
export declare const handleNotifyUser: (emit: NotifyEmitter, args: Static<typeof NotifyUserParams>) => string;
|
|
11
|
+
/** pi extension factory exposing the notify_user tool to the agent. */
|
|
12
|
+
export declare const createNotifyToolFactory: (emit: NotifyEmitter) => ExtensionFactory;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { StringEnum } from "@earendil-works/pi-ai";
|
|
2
|
+
import { Type } from "typebox";
|
|
3
|
+
import { NOTIFY_EVENT, SEVERITIES } from "./payload.js";
|
|
4
|
+
export const NotifyUserParams = Type.Object({
|
|
5
|
+
text: Type.String({ description: "The notification message to deliver to the user" }),
|
|
6
|
+
title: Type.Optional(Type.String({ description: "Optional short headline" })),
|
|
7
|
+
severity: Type.Optional(StringEnum(["info", "warning", "urgent"], {
|
|
8
|
+
description: "'urgent' is delivered immediately; 'info' (default) and 'warning' wait for an idle moment and may be batched into a digest",
|
|
9
|
+
})),
|
|
10
|
+
});
|
|
11
|
+
export const handleNotifyUser = (emit, args) => {
|
|
12
|
+
if (args.text.trim() === "")
|
|
13
|
+
throw new Error("Notification text cannot be empty.");
|
|
14
|
+
emit(NOTIFY_EVENT, {
|
|
15
|
+
title: args.title,
|
|
16
|
+
text: args.text,
|
|
17
|
+
severity: args.severity ?? SEVERITIES.info,
|
|
18
|
+
source: "agent",
|
|
19
|
+
});
|
|
20
|
+
return "Notification sent.";
|
|
21
|
+
};
|
|
22
|
+
/** pi extension factory exposing the notify_user tool to the agent. */
|
|
23
|
+
export const createNotifyToolFactory = (emit) => (pi) => {
|
|
24
|
+
pi.registerTool({
|
|
25
|
+
name: "notify_user",
|
|
26
|
+
label: "Notify User",
|
|
27
|
+
description: "Send a notification to the user outside the normal reply flow. Non-urgent notifications wait for an idle moment and may be combined into a digest; urgent ones are delivered immediately.",
|
|
28
|
+
promptSnippet: "Notify the user proactively (use sparingly; urgent severity interrupts)",
|
|
29
|
+
promptGuidelines: [
|
|
30
|
+
"Use notify_user only for information the user should see outside your direct reply; reserve severity 'urgent' for genuinely time-sensitive matters.",
|
|
31
|
+
],
|
|
32
|
+
parameters: NotifyUserParams,
|
|
33
|
+
async execute(_toolCallId, params) {
|
|
34
|
+
return {
|
|
35
|
+
content: [{ type: "text", text: handleNotifyUser(emit, params) }],
|
|
36
|
+
details: undefined,
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/extensions/notifications/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAsB,UAAU,EAAE,MAAM,cAAc,CAAC;AAI5E,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC;IAC1C,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,iDAAiD,EAAE,CAAC;IACrF,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,yBAAyB,EAAE,CAAC,CAAC;IAC7E,QAAQ,EAAE,IAAI,CAAC,QAAQ,CACrB,UAAU,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAU,EAAE;QACjD,WAAW,EACT,4HAA4H;KAC/H,CAAC,CACH;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,IAAmB,EACnB,IAAqC,EAC7B,EAAE;IACV,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IAEnF,IAAI,CAAC,YAAY,EAAE;QACjB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,UAAU,CAAC,IAAI;QAC1C,MAAM,EAAE,OAAO;KAChB,CAAC,CAAC;IAEH,OAAO,oBAAoB,CAAC;AAC9B,CAAC,CAAC;AAEF,uEAAuE;AACvE,MAAM,CAAC,MAAM,uBAAuB,GAClC,CAAC,IAAmB,EAAoB,EAAE,CAC1C,CAAC,EAAE,EAAE,EAAE;IACL,EAAE,CAAC,YAAY,CAAC;QACd,IAAI,EAAE,aAAa;QACnB,KAAK,EAAE,aAAa;QACpB,WAAW,EACT,2LAA2L;QAC7L,aAAa,EAAE,yEAAyE;QACxF,gBAAgB,EAAE;YAChB,qJAAqJ;SACtJ;QACD,UAAU,EAAE,gBAAgB;QAC5B,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM;YAC/B,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC;gBACjE,OAAO,EAAE,SAAS;aACnB,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Logger } from "../../log.ts";
|
|
2
|
+
import type { ContextProvider } from "../api.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Injects awareness of the registered projects: each submodule with its
|
|
5
|
+
* current branch (or detached commit) and uncommitted-change count. Always
|
|
6
|
+
* provides a block so the agent knows register_project is available even when
|
|
7
|
+
* no projects exist yet.
|
|
8
|
+
*/
|
|
9
|
+
export declare const createProjectsContextProvider: (workspaceRoot: string, log: Logger) => ContextProvider;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { describeProjectState, listSubmodules, projectState } from "./git.js";
|
|
2
|
+
/**
|
|
3
|
+
* Injects awareness of the registered projects: each submodule with its
|
|
4
|
+
* current branch (or detached commit) and uncommitted-change count. Always
|
|
5
|
+
* provides a block so the agent knows register_project is available even when
|
|
6
|
+
* no projects exist yet.
|
|
7
|
+
*/
|
|
8
|
+
export const createProjectsContextProvider = (workspaceRoot, log) => ({
|
|
9
|
+
name: "projects",
|
|
10
|
+
async provide() {
|
|
11
|
+
let submodulePaths;
|
|
12
|
+
try {
|
|
13
|
+
submodulePaths = await listSubmodules(workspaceRoot);
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
log.warn({ err: error }, "failed to list submodules");
|
|
17
|
+
submodulePaths = [];
|
|
18
|
+
}
|
|
19
|
+
if (submodulePaths.length === 0) {
|
|
20
|
+
return {
|
|
21
|
+
tag: "projects",
|
|
22
|
+
content: "No projects registered. Use register_project to add one.",
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const states = await Promise.allSettled(submodulePaths.map((path) => projectState(workspaceRoot, path)));
|
|
26
|
+
const lines = states
|
|
27
|
+
.filter((state) => state.status === "fulfilled")
|
|
28
|
+
.map((state) => describeProjectState(state.value));
|
|
29
|
+
for (const state of states) {
|
|
30
|
+
if (state.status === "rejected") {
|
|
31
|
+
log.warn({ err: state.reason }, "failed to get project info");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return { tag: "projects", content: `## Registered Projects\n\n${lines.join("\n")}` };
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=context-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-provider.js","sourceRoot":"","sources":["../../../src/extensions/projects/context-provider.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE9E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAC3C,aAAqB,EACrB,GAAW,EACM,EAAE,CAAC,CAAC;IACrB,IAAI,EAAE,UAAU;IAEhB,KAAK,CAAC,OAAO;QACX,IAAI,cAAwB,CAAC;QAE7B,IAAI,CAAC;YACH,cAAc,GAAG,MAAM,cAAc,CAAC,aAAa,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,2BAA2B,CAAC,CAAC;YACtD,cAAc,GAAG,EAAE,CAAC;QACtB,CAAC;QAED,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChC,OAAO;gBACL,GAAG,EAAE,UAAU;gBACf,OAAO,EAAE,0DAA0D;aACpE,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,CACrC,cAAc,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC,CAChE,CAAC;QAEF,MAAM,KAAK,GAAG,MAAM;aACjB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,WAAW,CAAC;aAC/C,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;QAErD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,KAAK,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;gBAChC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,MAAM,EAAE,EAAE,4BAA4B,CAAC,CAAC;YAChE,CAAC;QACH,CAAC;QAED,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,6BAA6B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;IACvF,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** List all registered submodule paths (e.g. ["projects/my-app"]) from git state. */
|
|
2
|
+
export declare const listSubmodules: (workspaceRoot: string) => Promise<string[]>;
|
|
3
|
+
export declare const initSubmodule: (workspaceRoot: string, path: string) => Promise<void>;
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the default branch from the remote's HEAD reference: local symbolic
|
|
6
|
+
* ref first, `git remote show origin` as a fallback, "main" as a last resort.
|
|
7
|
+
*/
|
|
8
|
+
export declare const resolveDefaultBranch: (repoPath: string) => Promise<string>;
|
|
9
|
+
export declare const checkoutBranch: (repoPath: string, branch: string) => Promise<void>;
|
|
10
|
+
/** Porcelain status output, or null when the working tree is clean. */
|
|
11
|
+
export declare const uncommittedChangesDetail: (repoPath: string) => Promise<string | null>;
|
|
12
|
+
export declare const isDirty: (repoPath: string) => Promise<boolean>;
|
|
13
|
+
export declare const addSubmodule: (workspaceRoot: string, name: string, url: string) => Promise<void>;
|
|
14
|
+
/** Remove a submodule completely: deinit, git rm, and drop the .git/modules clone. */
|
|
15
|
+
export declare const removeSubmodule: (workspaceRoot: string, name: string) => Promise<void>;
|
|
16
|
+
/** Current branch name, or null when HEAD is detached. */
|
|
17
|
+
export declare const currentBranch: (repoPath: string) => Promise<string | null>;
|
|
18
|
+
export declare const currentCommitShort: (repoPath: string) => Promise<string>;
|
|
19
|
+
export interface ProjectState {
|
|
20
|
+
name: string;
|
|
21
|
+
/** Branch name, or null when HEAD is detached. */
|
|
22
|
+
branch: string | null;
|
|
23
|
+
commit: string;
|
|
24
|
+
dirtyFiles: number;
|
|
25
|
+
}
|
|
26
|
+
/** Gather display state (branch/commit + dirty file count) for one submodule path. */
|
|
27
|
+
export declare const projectState: (workspaceRoot: string, path: string) => Promise<ProjectState>;
|
|
28
|
+
export declare const describeProjectState: (state: ProjectState) => string;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { rm } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { runGit, runGitCapture } from "../git/git.js";
|
|
4
|
+
/** List all registered submodule paths (e.g. ["projects/my-app"]) from git state. */
|
|
5
|
+
export const listSubmodules = async (workspaceRoot) => {
|
|
6
|
+
const result = await runGitCapture(workspaceRoot, ["submodule", "status", "--recursive"]);
|
|
7
|
+
if (result.code !== 0)
|
|
8
|
+
return [];
|
|
9
|
+
// Each line is like " abc1234 projects/my-app (heads/main)" — the first
|
|
10
|
+
// character is a status indicator (space, +, -, or U) fused to the hash.
|
|
11
|
+
return result.stdout
|
|
12
|
+
.split("\n")
|
|
13
|
+
.map((line) => line.trim().split(/\s+/))
|
|
14
|
+
.filter((parts) => parts.length >= 2)
|
|
15
|
+
.map((parts) => parts[1]);
|
|
16
|
+
};
|
|
17
|
+
export const initSubmodule = async (workspaceRoot, path) => {
|
|
18
|
+
await runGit(workspaceRoot, ["submodule", "update", "--init", path]);
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Resolve the default branch from the remote's HEAD reference: local symbolic
|
|
22
|
+
* ref first, `git remote show origin` as a fallback, "main" as a last resort.
|
|
23
|
+
*/
|
|
24
|
+
export const resolveDefaultBranch = async (repoPath) => {
|
|
25
|
+
const symbolic = await runGitCapture(repoPath, ["symbolic-ref", "refs/remotes/origin/HEAD"]);
|
|
26
|
+
const prefix = "refs/remotes/origin/";
|
|
27
|
+
if (symbolic.code === 0 && symbolic.stdout.startsWith(prefix)) {
|
|
28
|
+
return symbolic.stdout.slice(prefix.length);
|
|
29
|
+
}
|
|
30
|
+
const show = await runGitCapture(repoPath, ["remote", "show", "origin"]);
|
|
31
|
+
if (show.code === 0) {
|
|
32
|
+
const headLine = show.stdout.split("\n").find((line) => line.includes("HEAD branch:"));
|
|
33
|
+
if (headLine != null)
|
|
34
|
+
return (headLine.split(":").at(-1) ?? "").trim() || "main";
|
|
35
|
+
}
|
|
36
|
+
return "main";
|
|
37
|
+
};
|
|
38
|
+
export const checkoutBranch = async (repoPath, branch) => {
|
|
39
|
+
await runGit(repoPath, ["checkout", branch]);
|
|
40
|
+
};
|
|
41
|
+
/** Porcelain status output, or null when the working tree is clean. */
|
|
42
|
+
export const uncommittedChangesDetail = async (repoPath) => {
|
|
43
|
+
const { stdout } = await runGitCapture(repoPath, ["status", "--porcelain"]);
|
|
44
|
+
return stdout === "" ? null : stdout;
|
|
45
|
+
};
|
|
46
|
+
export const isDirty = async (repoPath) => (await uncommittedChangesDetail(repoPath)) != null;
|
|
47
|
+
export const addSubmodule = async (workspaceRoot, name, url) => {
|
|
48
|
+
await runGit(workspaceRoot, ["submodule", "add", url, `projects/${name}`]);
|
|
49
|
+
};
|
|
50
|
+
/** Remove a submodule completely: deinit, git rm, and drop the .git/modules clone. */
|
|
51
|
+
export const removeSubmodule = async (workspaceRoot, name) => {
|
|
52
|
+
const path = `projects/${name}`;
|
|
53
|
+
await runGit(workspaceRoot, ["submodule", "deinit", "-f", path]);
|
|
54
|
+
await runGit(workspaceRoot, ["rm", "-f", path]);
|
|
55
|
+
await rm(join(workspaceRoot, ".git", "modules", "projects", name), {
|
|
56
|
+
recursive: true,
|
|
57
|
+
force: true,
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
/** Current branch name, or null when HEAD is detached. */
|
|
61
|
+
export const currentBranch = async (repoPath) => {
|
|
62
|
+
const result = await runGitCapture(repoPath, ["symbolic-ref", "--short", "HEAD"]);
|
|
63
|
+
if (result.code !== 0 || result.stdout === "")
|
|
64
|
+
return null;
|
|
65
|
+
return result.stdout;
|
|
66
|
+
};
|
|
67
|
+
export const currentCommitShort = async (repoPath) => {
|
|
68
|
+
const result = await runGitCapture(repoPath, ["rev-parse", "--short", "HEAD"]);
|
|
69
|
+
if (result.code !== 0 || result.stdout === "")
|
|
70
|
+
return "unknown";
|
|
71
|
+
return result.stdout;
|
|
72
|
+
};
|
|
73
|
+
/** Gather display state (branch/commit + dirty file count) for one submodule path. */
|
|
74
|
+
export const projectState = async (workspaceRoot, path) => {
|
|
75
|
+
const repoPath = join(workspaceRoot, path);
|
|
76
|
+
const detail = await uncommittedChangesDetail(repoPath);
|
|
77
|
+
return {
|
|
78
|
+
name: path.split("/").at(-1) ?? path,
|
|
79
|
+
branch: await currentBranch(repoPath),
|
|
80
|
+
commit: await currentCommitShort(repoPath),
|
|
81
|
+
dirtyFiles: detail == null ? 0 : detail.split("\n").length,
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
export const describeProjectState = (state) => {
|
|
85
|
+
const location = state.branch ?? `${state.commit} (detached)`;
|
|
86
|
+
const dirty = state.dirtyFiles > 0
|
|
87
|
+
? ` — ${state.dirtyFiles} uncommitted change${state.dirtyFiles === 1 ? "" : "s"}`
|
|
88
|
+
: "";
|
|
89
|
+
return `- ${state.name}: ${location}${dirty}`;
|
|
90
|
+
};
|
|
91
|
+
//# sourceMappingURL=git.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../../src/extensions/projects/git.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Logger } from "../../log.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Bootstrap hook: ensure the projects directory exists, then initialize and
|
|
4
|
+
* sync every registered submodule (init → default branch checkout → pull) in
|
|
5
|
+
* parallel with per-submodule error isolation and one retry each.
|
|
6
|
+
*/
|
|
7
|
+
export declare const syncProjects: (workspaceRoot: string, log: Logger) => Promise<void>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { mkdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { smartPull } from "../git/sync.js";
|
|
4
|
+
import { checkoutBranch, initSubmodule, listSubmodules, resolveDefaultBranch } from "./git.js";
|
|
5
|
+
const syncSubmodule = async (workspaceRoot, path, log) => {
|
|
6
|
+
const repoPath = join(workspaceRoot, path);
|
|
7
|
+
await initSubmodule(workspaceRoot, path);
|
|
8
|
+
const defaultBranch = await resolveDefaultBranch(repoPath);
|
|
9
|
+
await checkoutBranch(repoPath, defaultBranch);
|
|
10
|
+
const result = await smartPull(repoPath, "origin", defaultBranch, log);
|
|
11
|
+
log.info({ path, result }, "submodule synced");
|
|
12
|
+
};
|
|
13
|
+
const syncSubmoduleWithRetry = async (workspaceRoot, path, log) => {
|
|
14
|
+
try {
|
|
15
|
+
await syncSubmodule(workspaceRoot, path, log);
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
log.debug({ path, err: error }, "submodule sync failed — retrying");
|
|
19
|
+
await syncSubmodule(workspaceRoot, path, log);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Bootstrap hook: ensure the projects directory exists, then initialize and
|
|
24
|
+
* sync every registered submodule (init → default branch checkout → pull) in
|
|
25
|
+
* parallel with per-submodule error isolation and one retry each.
|
|
26
|
+
*/
|
|
27
|
+
export const syncProjects = async (workspaceRoot, log) => {
|
|
28
|
+
await mkdir(join(workspaceRoot, "projects"), { recursive: true });
|
|
29
|
+
const submodulePaths = await listSubmodules(workspaceRoot);
|
|
30
|
+
if (submodulePaths.length === 0) {
|
|
31
|
+
log.debug("no submodules found — skipping sync");
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
log.info({ count: submodulePaths.length, paths: submodulePaths }, "syncing submodules");
|
|
35
|
+
const results = await Promise.allSettled(submodulePaths.map((path) => syncSubmoduleWithRetry(workspaceRoot, path, log)));
|
|
36
|
+
for (const [index, result] of results.entries()) {
|
|
37
|
+
if (result.status === "rejected") {
|
|
38
|
+
log.warn({ path: submodulePaths[index], err: result.reason }, "submodule sync failed after retry");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../../src/extensions/projects/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAE/F,MAAM,aAAa,GAAG,KAAK,EAAE,aAAqB,EAAE,IAAY,EAAE,GAAW,EAAiB,EAAE;IAC9F,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;IAE3C,MAAM,aAAa,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;IAEzC,MAAM,aAAa,GAAG,MAAM,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAC3D,MAAM,cAAc,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;IAE9C,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAG,CAAC,CAAC;IACvE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,kBAAkB,CAAC,CAAC;AACjD,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAG,KAAK,EAClC,aAAqB,EACrB,IAAY,EACZ,GAAW,EACI,EAAE;IACjB,IAAI,CAAC;QACH,MAAM,aAAa,CAAC,aAAa,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;IAChD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,kCAAkC,CAAC,CAAC;QACpE,MAAM,aAAa,CAAC,aAAa,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;IAChD,CAAC;AACH,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAAE,aAAqB,EAAE,GAAW,EAAiB,EAAE;IACtF,MAAM,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAElE,MAAM,cAAc,GAAG,MAAM,cAAc,CAAC,aAAa,CAAC,CAAC;IAE3D,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,GAAG,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACjD,OAAO;IACT,CAAC;IAED,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,oBAAoB,CAAC,CAAC;IAExF,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CACtC,cAAc,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,sBAAsB,CAAC,aAAa,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAC/E,CAAC;IAEF,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;QAChD,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YACjC,GAAG,CAAC,IAAI,CACN,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,EACnD,mCAAmC,CACpC,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface ProjectsConfig {
|
|
2
|
+
enabled: boolean;
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* External project management: registers git repositories as submodules under
|
|
6
|
+
* projects/, syncs them on startup, surfaces their git state on every message,
|
|
7
|
+
* and commits + pushes dirty projects at session close (before the workspace
|
|
8
|
+
* commit, so submodule pointer updates land in the same pass).
|
|
9
|
+
*/
|
|
10
|
+
declare const _default: import("../api.ts").TachikomaExtension<ProjectsConfig>;
|
|
11
|
+
export default _default;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import { defineExtension } from "../api.js";
|
|
3
|
+
import { createProjectsContextProvider } from "./context-provider.js";
|
|
4
|
+
import { syncProjects } from "./hooks.js";
|
|
5
|
+
import { createProjectsProcessor } from "./processor.js";
|
|
6
|
+
import { createProjectsToolsFactory } from "./tools.js";
|
|
7
|
+
/**
|
|
8
|
+
* External project management: registers git repositories as submodules under
|
|
9
|
+
* projects/, syncs them on startup, surfaces their git state on every message,
|
|
10
|
+
* and commits + pushes dirty projects at session close (before the workspace
|
|
11
|
+
* commit, so submodule pointer updates land in the same pass).
|
|
12
|
+
*/
|
|
13
|
+
export default defineExtension({
|
|
14
|
+
name: "projects",
|
|
15
|
+
configSchema: Type.Object({
|
|
16
|
+
enabled: Type.Boolean({ default: true }),
|
|
17
|
+
}),
|
|
18
|
+
setup(app) {
|
|
19
|
+
if (!app.extensionConfig.enabled) {
|
|
20
|
+
app.log.info("projects extension disabled by configuration");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const workspaceRoot = app.workspace.root;
|
|
24
|
+
app.bootstrap("sync-projects", () => syncProjects(workspaceRoot, app.log));
|
|
25
|
+
app.agent.provideContext(createProjectsContextProvider(workspaceRoot, app.log));
|
|
26
|
+
app.agent.use(createProjectsToolsFactory({ workspaceRoot, log: app.log }));
|
|
27
|
+
app.sessions.registerProcessor(createProjectsProcessor({ workspaceRoot, side: app.agent.side }));
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/projects/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,6BAA6B,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAMxD;;;;;GAKG;AACH,eAAe,eAAe,CAAiB;IAC7C,IAAI,EAAE,UAAU;IAEhB,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC;QACxB,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;KACzC,CAAC;IAEF,KAAK,CAAC,GAAG;QACP,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC;YACjC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;YAC7D,OAAO;QACT,CAAC;QAED,MAAM,aAAa,GAAG,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC;QAEzC,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,aAAa,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAE3E,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,6BAA6B,CAAC,aAAa,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAChF,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,0BAA0B,CAAC,EAAE,aAAa,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAE3E,GAAG,CAAC,QAAQ,CAAC,iBAAiB,CAC5B,uBAAuB,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CACjE,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PostProcessor } from "../api.ts";
|
|
2
|
+
import { type Completer } from "../git/commit.ts";
|
|
3
|
+
export interface ProjectsProcessorDeps {
|
|
4
|
+
workspaceRoot: string;
|
|
5
|
+
side: Completer;
|
|
6
|
+
}
|
|
7
|
+
export declare const projectFallbackMessage: (name: string, now?: Date) => string;
|
|
8
|
+
/**
|
|
9
|
+
* Pre-finalize post-processor: commits and pushes every dirty registered
|
|
10
|
+
* project before the workspace commit runs, so submodule pointer updates land
|
|
11
|
+
* in the same workspace commit pass.
|
|
12
|
+
*/
|
|
13
|
+
export declare const createProjectsProcessor: ({ workspaceRoot, side, }: ProjectsProcessorDeps) => PostProcessor;
|