@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,63 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { commitAll } from "../git/commit.js";
|
|
3
|
+
import { PUSH_SUCCESS, smartPush } from "../git/sync.js";
|
|
4
|
+
import { isDirty, listSubmodules } from "./git.js";
|
|
5
|
+
export const projectFallbackMessage = (name, now = new Date()) => `Update ${name} files (${now.toISOString().slice(0, 10)})`;
|
|
6
|
+
const commitAndPush = async (workspaceRoot, side, path, log) => {
|
|
7
|
+
const repoPath = join(workspaceRoot, path);
|
|
8
|
+
const name = path.split("/").at(-1) ?? path;
|
|
9
|
+
const message = await commitAll({
|
|
10
|
+
cwd: repoPath,
|
|
11
|
+
side,
|
|
12
|
+
fallbackMessage: projectFallbackMessage(name),
|
|
13
|
+
log,
|
|
14
|
+
});
|
|
15
|
+
if (message != null)
|
|
16
|
+
log.info({ path, message }, "committed project changes");
|
|
17
|
+
const result = await smartPush(repoPath, "origin", "HEAD", log);
|
|
18
|
+
if (PUSH_SUCCESS.has(result)) {
|
|
19
|
+
log.info({ path, result }, "pushed project changes");
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
log.warn({ path, result }, "push failed — changes remain committed locally");
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Pre-finalize post-processor: commits and pushes every dirty registered
|
|
27
|
+
* project before the workspace commit runs, so submodule pointer updates land
|
|
28
|
+
* in the same workspace commit pass.
|
|
29
|
+
*/
|
|
30
|
+
export const createProjectsProcessor = ({ workspaceRoot, side, }) => ({
|
|
31
|
+
name: "projects-commit",
|
|
32
|
+
phase: "preFinalize",
|
|
33
|
+
async process({ log }) {
|
|
34
|
+
const submodulePaths = await listSubmodules(workspaceRoot);
|
|
35
|
+
if (submodulePaths.length === 0) {
|
|
36
|
+
log.debug("no submodules found — skipping project processing");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const dirtyChecks = await Promise.allSettled(submodulePaths.map((path) => isDirty(join(workspaceRoot, path))));
|
|
40
|
+
const dirtyPaths = [];
|
|
41
|
+
for (const [index, check] of dirtyChecks.entries()) {
|
|
42
|
+
const path = submodulePaths[index];
|
|
43
|
+
if (check.status === "rejected") {
|
|
44
|
+
log.warn({ path, err: check.reason }, "failed to check submodule status");
|
|
45
|
+
}
|
|
46
|
+
else if (check.value) {
|
|
47
|
+
dirtyPaths.push(path);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (dirtyPaths.length === 0) {
|
|
51
|
+
log.debug("no dirty submodules — skipping commit");
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
log.info({ paths: dirtyPaths }, "processing dirty submodules");
|
|
55
|
+
const results = await Promise.allSettled(dirtyPaths.map((path) => commitAndPush(workspaceRoot, side, path, log)));
|
|
56
|
+
for (const [index, result] of results.entries()) {
|
|
57
|
+
if (result.status === "rejected") {
|
|
58
|
+
log.warn({ path: dirtyPaths[index], err: result.reason }, "failed to process submodule");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
//# sourceMappingURL=processor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processor.js","sourceRoot":"","sources":["../../../src/extensions/projects/processor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ExtensionFactory } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { type Static, Type } from "typebox";
|
|
3
|
+
import type { Logger } from "../../log.ts";
|
|
4
|
+
export interface ProjectToolDeps {
|
|
5
|
+
workspaceRoot: string;
|
|
6
|
+
log: Logger;
|
|
7
|
+
}
|
|
8
|
+
export declare const RegisterProjectParams: Type.TObject<{
|
|
9
|
+
name: Type.TString;
|
|
10
|
+
url: Type.TString;
|
|
11
|
+
}>;
|
|
12
|
+
export declare const DeregisterProjectParams: Type.TObject<{
|
|
13
|
+
name: Type.TString;
|
|
14
|
+
force: Type.TOptional<Type.TBoolean>;
|
|
15
|
+
}>;
|
|
16
|
+
export declare const ListProjectsParams: Type.TObject<{}>;
|
|
17
|
+
export declare const handleRegisterProject: ({ workspaceRoot, log }: ProjectToolDeps, args: Static<typeof RegisterProjectParams>) => Promise<string>;
|
|
18
|
+
export declare const handleDeregisterProject: ({ workspaceRoot, log }: ProjectToolDeps, args: Static<typeof DeregisterProjectParams>) => Promise<string>;
|
|
19
|
+
export declare const handleListProjects: ({ workspaceRoot }: ProjectToolDeps) => Promise<string>;
|
|
20
|
+
/** pi extension factory exposing the project management tools to the agent. */
|
|
21
|
+
export declare const createProjectsToolsFactory: (deps: ProjectToolDeps) => ExtensionFactory;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { access } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { Type } from "typebox";
|
|
4
|
+
import { addSubmodule, checkoutBranch, describeProjectState, listSubmodules, projectState, removeSubmodule, resolveDefaultBranch, uncommittedChangesDetail, } from "./git.js";
|
|
5
|
+
export const RegisterProjectParams = Type.Object({
|
|
6
|
+
name: Type.String({ description: "Project name — becomes the directory under projects/" }),
|
|
7
|
+
url: Type.String({ description: "Git remote URL to clone the project from" }),
|
|
8
|
+
});
|
|
9
|
+
export const DeregisterProjectParams = Type.Object({
|
|
10
|
+
name: Type.String({ description: "Name of the registered project to remove" }),
|
|
11
|
+
force: Type.Optional(Type.Boolean({
|
|
12
|
+
description: "Remove even when the project has uncommitted changes (they will be lost)",
|
|
13
|
+
})),
|
|
14
|
+
});
|
|
15
|
+
export const ListProjectsParams = Type.Object({});
|
|
16
|
+
const exists = async (path) => access(path).then(() => true, () => false);
|
|
17
|
+
export const handleRegisterProject = async ({ workspaceRoot, log }, args) => {
|
|
18
|
+
if (args.name === "")
|
|
19
|
+
throw new Error("'name' is required");
|
|
20
|
+
if (args.url === "")
|
|
21
|
+
throw new Error("'url' is required");
|
|
22
|
+
const projectPath = join(workspaceRoot, "projects", args.name);
|
|
23
|
+
if (await exists(projectPath))
|
|
24
|
+
throw new Error(`Project '${args.name}' already exists`);
|
|
25
|
+
try {
|
|
26
|
+
await addSubmodule(workspaceRoot, args.name, args.url);
|
|
27
|
+
const defaultBranch = await resolveDefaultBranch(projectPath);
|
|
28
|
+
await checkoutBranch(projectPath, defaultBranch);
|
|
29
|
+
log.info({ name: args.name, url: args.url, branch: defaultBranch }, "project registered");
|
|
30
|
+
return (`Registered project '${args.name}' (branch: ${defaultBranch}). ` +
|
|
31
|
+
`The project is now available under projects/${args.name}. ` +
|
|
32
|
+
"Changes will be committed to the workspace at session end.");
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (await exists(projectPath)) {
|
|
36
|
+
try {
|
|
37
|
+
await removeSubmodule(workspaceRoot, args.name);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// Partial-state cleanup is best-effort; the original error matters more.
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
log.warn({ name: args.name, err: error }, "project registration failed");
|
|
44
|
+
throw new Error(`Error registering project: ${error.message}`);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
export const handleDeregisterProject = async ({ workspaceRoot, log }, args) => {
|
|
48
|
+
if (args.name === "")
|
|
49
|
+
throw new Error("'name' is required");
|
|
50
|
+
const projectPath = join(workspaceRoot, "projects", args.name);
|
|
51
|
+
if (!(await exists(projectPath)))
|
|
52
|
+
throw new Error(`Project '${args.name}' not found`);
|
|
53
|
+
const force = args.force ?? false;
|
|
54
|
+
const changes = await uncommittedChangesDetail(projectPath);
|
|
55
|
+
if (changes != null && !force) {
|
|
56
|
+
throw new Error(`Project '${args.name}' has uncommitted changes:\n${changes}\n\n` +
|
|
57
|
+
"Use force=true to remove anyway (changes will be lost).");
|
|
58
|
+
}
|
|
59
|
+
await removeSubmodule(workspaceRoot, args.name);
|
|
60
|
+
log.info({ name: args.name, force }, "project deregistered");
|
|
61
|
+
return (`Deregistered project '${args.name}'. ` +
|
|
62
|
+
"Changes will be committed to the workspace at session end.");
|
|
63
|
+
};
|
|
64
|
+
export const handleListProjects = async ({ workspaceRoot }) => {
|
|
65
|
+
const submodulePaths = await listSubmodules(workspaceRoot);
|
|
66
|
+
if (submodulePaths.length === 0) {
|
|
67
|
+
return "No projects registered. Use register_project to add one.";
|
|
68
|
+
}
|
|
69
|
+
const lines = await Promise.all(submodulePaths.map(async (path) => describeProjectState(await projectState(workspaceRoot, path))));
|
|
70
|
+
return `# Registered Projects\n\n${lines.join("\n")}`;
|
|
71
|
+
};
|
|
72
|
+
const textResult = (text) => ({
|
|
73
|
+
content: [{ type: "text", text }],
|
|
74
|
+
details: undefined,
|
|
75
|
+
});
|
|
76
|
+
/** pi extension factory exposing the project management tools to the agent. */
|
|
77
|
+
export const createProjectsToolsFactory = (deps) => (pi) => {
|
|
78
|
+
pi.registerTool({
|
|
79
|
+
name: "register_project",
|
|
80
|
+
label: "Register Project",
|
|
81
|
+
description: "Register an external git repository as a project: clones it as a submodule under projects/<name> and checks out its default branch. Project changes are committed and pushed automatically at session end.",
|
|
82
|
+
promptSnippet: "Register an external git repository as a tracked project",
|
|
83
|
+
promptGuidelines: [
|
|
84
|
+
"Use register_project when the user wants to work on an external repository inside the workspace.",
|
|
85
|
+
],
|
|
86
|
+
parameters: RegisterProjectParams,
|
|
87
|
+
async execute(_toolCallId, params) {
|
|
88
|
+
return textResult(await handleRegisterProject(deps, params));
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
pi.registerTool({
|
|
92
|
+
name: "deregister_project",
|
|
93
|
+
label: "Deregister Project",
|
|
94
|
+
description: "Remove a registered project from the workspace. Fails when the project has uncommitted changes unless force=true is passed (those changes are lost).",
|
|
95
|
+
promptSnippet: "Remove a registered project from the workspace",
|
|
96
|
+
promptGuidelines: [
|
|
97
|
+
"Confirm with the user before calling deregister_project with force=true — uncommitted work is lost.",
|
|
98
|
+
],
|
|
99
|
+
parameters: DeregisterProjectParams,
|
|
100
|
+
async execute(_toolCallId, params) {
|
|
101
|
+
return textResult(await handleDeregisterProject(deps, params));
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
pi.registerTool({
|
|
105
|
+
name: "list_projects",
|
|
106
|
+
label: "List Projects",
|
|
107
|
+
description: "List the registered projects with their current branch (or detached commit) and uncommitted-change counts.",
|
|
108
|
+
promptSnippet: "List registered projects and their git state",
|
|
109
|
+
promptGuidelines: [
|
|
110
|
+
"Check list_projects before register_project to avoid registering a duplicate.",
|
|
111
|
+
],
|
|
112
|
+
parameters: ListProjectsParams,
|
|
113
|
+
async execute() {
|
|
114
|
+
return textResult(await handleListProjects(deps));
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/extensions/projects/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ExtensionFactory } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import type { Channel } from "../channels/types.ts";
|
|
3
|
+
import type { SessionRecord } from "../db/core-schema.ts";
|
|
4
|
+
import type { ContextProvider, ExchangeProcessor, InboundMiddleware, PostProcessor } from "./api.ts";
|
|
5
|
+
export interface BootstrapHook {
|
|
6
|
+
name: string;
|
|
7
|
+
hook: () => void | Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
/** Mutable registries filled by extensions during setup and read by core at runtime. */
|
|
10
|
+
export interface Registrations {
|
|
11
|
+
piFactories: ExtensionFactory[];
|
|
12
|
+
systemPromptBuilders: (() => string)[];
|
|
13
|
+
contextProviders: ContextProvider[];
|
|
14
|
+
exchangeProcessors: ExchangeProcessor[];
|
|
15
|
+
postProcessors: PostProcessor[];
|
|
16
|
+
inboundMiddleware: InboundMiddleware[];
|
|
17
|
+
sessionOpenHooks: ((session: SessionRecord) => void | Promise<void>)[];
|
|
18
|
+
channels: Map<string, Channel>;
|
|
19
|
+
bootstrapHooks: BootstrapHook[];
|
|
20
|
+
}
|
|
21
|
+
export declare const createRegistrations: () => Registrations;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const createRegistrations = () => ({
|
|
2
|
+
piFactories: [],
|
|
3
|
+
systemPromptBuilders: [],
|
|
4
|
+
contextProviders: [],
|
|
5
|
+
exchangeProcessors: [],
|
|
6
|
+
postProcessors: [],
|
|
7
|
+
inboundMiddleware: [],
|
|
8
|
+
sessionOpenHooks: [],
|
|
9
|
+
channels: new Map(),
|
|
10
|
+
bootstrapHooks: [],
|
|
11
|
+
});
|
|
12
|
+
//# sourceMappingURL=registrations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registrations.js","sourceRoot":"","sources":["../../src/extensions/registrations.ts"],"names":[],"mappings":"AA6BA,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAkB,EAAE,CAAC,CAAC;IACvD,WAAW,EAAE,EAAE;IACf,oBAAoB,EAAE,EAAE;IACxB,gBAAgB,EAAE,EAAE;IACpB,kBAAkB,EAAE,EAAE;IACtB,cAAc,EAAE,EAAE;IAClB,iBAAiB,EAAE,EAAE;IACrB,gBAAgB,EAAE,EAAE;IACpB,QAAQ,EAAE,IAAI,GAAG,EAAE;IACnB,cAAc,EAAE,EAAE;CACnB,CAAC,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { createInterface } from "node:readline";
|
|
2
|
+
import { textMessage } from "../../domain/message.js";
|
|
3
|
+
import { defineExtension } from "../api.js";
|
|
4
|
+
const DIM = "\x1b[2m";
|
|
5
|
+
const RED = "\x1b[31m";
|
|
6
|
+
const RESET = "\x1b[0m";
|
|
7
|
+
class ReplChannel {
|
|
8
|
+
name = "repl";
|
|
9
|
+
readline = null;
|
|
10
|
+
async start(runtime) {
|
|
11
|
+
this.readline = createInterface({
|
|
12
|
+
input: process.stdin,
|
|
13
|
+
output: process.stdout,
|
|
14
|
+
prompt: "you> ",
|
|
15
|
+
});
|
|
16
|
+
this.readline.on("line", (line) => {
|
|
17
|
+
const text = line.trim();
|
|
18
|
+
if (text.length > 0) {
|
|
19
|
+
runtime.submit(textMessage(this.name, text));
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
this.readline?.prompt();
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
this.readline.on("close", () => {
|
|
26
|
+
// Pending exchanges must not touch the closed interface while shutdown runs.
|
|
27
|
+
this.readline = null;
|
|
28
|
+
process.kill(process.pid, "SIGINT");
|
|
29
|
+
});
|
|
30
|
+
this.readline.prompt();
|
|
31
|
+
}
|
|
32
|
+
async respond({ events }) {
|
|
33
|
+
let inText = false;
|
|
34
|
+
for await (const event of events) {
|
|
35
|
+
switch (event.kind) {
|
|
36
|
+
case "text":
|
|
37
|
+
process.stdout.write(event.text);
|
|
38
|
+
inText = true;
|
|
39
|
+
break;
|
|
40
|
+
case "tool-start":
|
|
41
|
+
if (inText)
|
|
42
|
+
process.stdout.write("\n");
|
|
43
|
+
process.stdout.write(`${DIM}⚙ ${event.toolName}${RESET}\n`);
|
|
44
|
+
inText = false;
|
|
45
|
+
break;
|
|
46
|
+
case "status":
|
|
47
|
+
if (inText)
|
|
48
|
+
process.stdout.write("\n");
|
|
49
|
+
process.stdout.write(`${DIM}${event.text}${RESET}\n`);
|
|
50
|
+
inText = false;
|
|
51
|
+
break;
|
|
52
|
+
case "error":
|
|
53
|
+
if (inText)
|
|
54
|
+
process.stdout.write("\n");
|
|
55
|
+
process.stdout.write(`${RED}error: ${event.message}${RESET}\n`);
|
|
56
|
+
inText = false;
|
|
57
|
+
break;
|
|
58
|
+
case "result":
|
|
59
|
+
process.stdout.write("\n");
|
|
60
|
+
this.readline?.prompt();
|
|
61
|
+
break;
|
|
62
|
+
default:
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async deliver(delivery) {
|
|
68
|
+
process.stdout.write(`\n📥 ${delivery.text}\n`);
|
|
69
|
+
this.readline?.prompt();
|
|
70
|
+
}
|
|
71
|
+
status(text) {
|
|
72
|
+
process.stdout.write(`${DIM}· ${text}${RESET}\n`);
|
|
73
|
+
}
|
|
74
|
+
async stop() {
|
|
75
|
+
this.readline?.close();
|
|
76
|
+
this.readline = null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export default defineExtension({
|
|
80
|
+
name: "repl",
|
|
81
|
+
setup(app) {
|
|
82
|
+
app.channels.register(new ReplChannel());
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/repl/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Logger } from "../../log.ts";
|
|
2
|
+
export interface SkillAgent {
|
|
3
|
+
/** Namespaced as "<skill>/<agent>" to prevent collisions across skills. */
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
tools: string[] | null;
|
|
7
|
+
systemPrompt: string;
|
|
8
|
+
skill: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Discover agent definitions bundled inside skill packages: markdown files under
|
|
12
|
+
* each skill's agents/ directory, with frontmatter metadata (description required;
|
|
13
|
+
* name and tools optional) and the body as the agent's system prompt.
|
|
14
|
+
*
|
|
15
|
+
* Invalid agent files are logged and skipped so one bad definition never blocks the rest.
|
|
16
|
+
*/
|
|
17
|
+
export declare const discoverSkillAgents: (skillsRoot: string, log: Logger) => SkillAgent[];
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { readdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { parseFrontmatter } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
const listDirectories = (path) => {
|
|
5
|
+
try {
|
|
6
|
+
return readdirSync(path, { withFileTypes: true })
|
|
7
|
+
.filter((entry) => entry.isDirectory())
|
|
8
|
+
.map((entry) => entry.name);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const listMarkdownFiles = (path) => {
|
|
15
|
+
try {
|
|
16
|
+
return readdirSync(path, { withFileTypes: true })
|
|
17
|
+
.filter((entry) => (entry.isFile() || entry.isSymbolicLink()) && entry.name.endsWith(".md"))
|
|
18
|
+
.map((entry) => entry.name);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
// Accepts both a YAML list and the comma-separated string used by pi's subagent example.
|
|
25
|
+
const parseTools = (raw) => {
|
|
26
|
+
if (raw == null)
|
|
27
|
+
return null;
|
|
28
|
+
if (typeof raw === "string") {
|
|
29
|
+
const tools = raw
|
|
30
|
+
.split(",")
|
|
31
|
+
.map((tool) => tool.trim())
|
|
32
|
+
.filter((tool) => tool.length > 0);
|
|
33
|
+
return tools.length > 0 ? tools : null;
|
|
34
|
+
}
|
|
35
|
+
if (Array.isArray(raw) && raw.every((tool) => typeof tool === "string")) {
|
|
36
|
+
return raw.length > 0 ? raw : null;
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Discover agent definitions bundled inside skill packages: markdown files under
|
|
42
|
+
* each skill's agents/ directory, with frontmatter metadata (description required;
|
|
43
|
+
* name and tools optional) and the body as the agent's system prompt.
|
|
44
|
+
*
|
|
45
|
+
* Invalid agent files are logged and skipped so one bad definition never blocks the rest.
|
|
46
|
+
*/
|
|
47
|
+
export const discoverSkillAgents = (skillsRoot, log) => {
|
|
48
|
+
const agents = [];
|
|
49
|
+
for (const skill of listDirectories(skillsRoot)) {
|
|
50
|
+
const agentsDir = join(skillsRoot, skill, "agents");
|
|
51
|
+
for (const file of listMarkdownFiles(agentsDir)) {
|
|
52
|
+
try {
|
|
53
|
+
const { frontmatter, body } = parseFrontmatter(readFileSync(join(agentsDir, file), "utf8"));
|
|
54
|
+
if (typeof frontmatter.description !== "string" || frontmatter.description.length === 0) {
|
|
55
|
+
log.warn({ skill, agent: file }, "skill agent missing description — skipped");
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const stem = file.slice(0, -".md".length);
|
|
59
|
+
const name = typeof frontmatter.name === "string" && frontmatter.name.length > 0
|
|
60
|
+
? frontmatter.name
|
|
61
|
+
: stem;
|
|
62
|
+
agents.push({
|
|
63
|
+
name: `${skill}/${name}`,
|
|
64
|
+
description: frontmatter.description,
|
|
65
|
+
tools: parseTools(frontmatter.tools),
|
|
66
|
+
systemPrompt: body,
|
|
67
|
+
skill,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
log.warn({ err: error, skill, agent: file }, "failed to load skill agent — skipped");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return agents;
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=agents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../../src/extensions/skills/agents.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { Type } from "typebox";
|
|
3
|
+
import type { SideRunner } from "../../agent/side-run.ts";
|
|
4
|
+
import type { Logger } from "../../log.ts";
|
|
5
|
+
import type { SkillAgent } from "./agents.ts";
|
|
6
|
+
export type AgentRunner = Pick<SideRunner, "run">;
|
|
7
|
+
export interface DelegateToolOptions {
|
|
8
|
+
/** Called once for the tool description and again on every execution (skills can change). */
|
|
9
|
+
discover: () => SkillAgent[];
|
|
10
|
+
runner: AgentRunner;
|
|
11
|
+
log: Logger;
|
|
12
|
+
}
|
|
13
|
+
declare const DelegateParams: Type.TObject<{
|
|
14
|
+
agent: Type.TString;
|
|
15
|
+
task: Type.TString;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* `delegate_to_agent`: run a skill-bundled agent definition headlessly with its own
|
|
19
|
+
* system prompt and tool set, returning the agent's final answer.
|
|
20
|
+
*/
|
|
21
|
+
export declare const createDelegateTool: ({ discover, runner, log, }: DelegateToolOptions) => ToolDefinition<typeof DelegateParams>;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { truncateTail } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { Type } from "typebox";
|
|
3
|
+
const DEFAULT_AGENT_TOOLS = ["read", "grep", "find", "ls"];
|
|
4
|
+
const DelegateParams = Type.Object({
|
|
5
|
+
agent: Type.String({
|
|
6
|
+
description: "Agent to delegate to, exactly as listed in the tool description",
|
|
7
|
+
}),
|
|
8
|
+
task: Type.String({
|
|
9
|
+
description: "Complete, self-contained task description — the agent has no access to this conversation",
|
|
10
|
+
}),
|
|
11
|
+
});
|
|
12
|
+
const renderAgentList = (agents) => agents.length > 0
|
|
13
|
+
? agents.map((agent) => `- ${agent.name}: ${agent.description}`).join("\n")
|
|
14
|
+
: "(none discovered)";
|
|
15
|
+
/**
|
|
16
|
+
* `delegate_to_agent`: run a skill-bundled agent definition headlessly with its own
|
|
17
|
+
* system prompt and tool set, returning the agent's final answer.
|
|
18
|
+
*/
|
|
19
|
+
export const createDelegateTool = ({ discover, runner, log, }) => ({
|
|
20
|
+
name: "delegate_to_agent",
|
|
21
|
+
label: "Delegate to agent",
|
|
22
|
+
description: [
|
|
23
|
+
"Delegate a focused task to a specialized agent bundled with a skill.",
|
|
24
|
+
"The agent runs in an isolated context with its own system prompt and tools,",
|
|
25
|
+
"and returns its final answer as the tool result.",
|
|
26
|
+
"",
|
|
27
|
+
"Available agents:",
|
|
28
|
+
renderAgentList(discover()),
|
|
29
|
+
].join("\n"),
|
|
30
|
+
promptSnippet: "delegate_to_agent: hand a focused task to a specialized skill-bundled agent",
|
|
31
|
+
promptGuidelines: [
|
|
32
|
+
"Use delegate_to_agent when a skill ships an agent suited to the task; pass a complete, self-contained task description.",
|
|
33
|
+
],
|
|
34
|
+
parameters: DelegateParams,
|
|
35
|
+
async execute(_toolCallId, params) {
|
|
36
|
+
const agents = discover();
|
|
37
|
+
const agent = agents.find((candidate) => candidate.name === params.agent);
|
|
38
|
+
if (agent == null) {
|
|
39
|
+
throw new Error(`Unknown agent "${params.agent}". Available agents:\n${renderAgentList(agents)}`);
|
|
40
|
+
}
|
|
41
|
+
log.debug({ agent: agent.name }, "delegating task to skill agent");
|
|
42
|
+
const result = await runner.run({
|
|
43
|
+
system: agent.systemPrompt,
|
|
44
|
+
tools: agent.tools ?? DEFAULT_AGENT_TOOLS,
|
|
45
|
+
prompt: params.task,
|
|
46
|
+
});
|
|
47
|
+
const { content, truncated } = truncateTail(result.text);
|
|
48
|
+
return {
|
|
49
|
+
content: [{ type: "text", text: truncated ? `${content}\n\n[output truncated]` : content }],
|
|
50
|
+
details: undefined,
|
|
51
|
+
};
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
//# sourceMappingURL=delegate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegate.js","sourceRoot":"","sources":["../../../src/extensions/skills/delegate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,YAAY,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAe/B,MAAM,mBAAmB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;AAE3D,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC;IACjC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC;QACjB,WAAW,EAAE,iEAAiE;KAC/E,CAAC;IACF,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC;QAChB,WAAW,EACT,0FAA0F;KAC7F,CAAC;CACH,CAAC,CAAC;AAEH,MAAM,eAAe,GAAG,CAAC,MAAoB,EAAU,EAAE,CACvD,MAAM,CAAC,MAAM,GAAG,CAAC;IACf,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IAC3E,CAAC,CAAC,mBAAmB,CAAC;AAE1B;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,EACjC,QAAQ,EACR,MAAM,EACN,GAAG,GACiB,EAAyC,EAAE,CAAC,CAAC;IACjE,IAAI,EAAE,mBAAmB;IACzB,KAAK,EAAE,mBAAmB;IAE1B,WAAW,EAAE;QACX,sEAAsE;QACtE,6EAA6E;QAC7E,kDAAkD;QAClD,EAAE;QACF,mBAAmB;QACnB,eAAe,CAAC,QAAQ,EAAE,CAAC;KAC5B,CAAC,IAAI,CAAC,IAAI,CAAC;IAEZ,aAAa,EAAE,6EAA6E;IAC5F,gBAAgB,EAAE;QAChB,yHAAyH;KAC1H;IAED,UAAU,EAAE,cAAc;IAE1B,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM;QAC/B,MAAM,MAAM,GAAG,QAAQ,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,MAAM,CAAC,KAAK,CAAC,CAAC;QAE1E,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CACb,kBAAkB,MAAM,CAAC,KAAK,yBAAyB,eAAe,CAAC,MAAM,CAAC,EAAE,CACjF,CAAC;QACJ,CAAC;QAED,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,gCAAgC,CAAC,CAAC;QAEnE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC;YAC9B,MAAM,EAAE,KAAK,CAAC,YAAY;YAC1B,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,mBAAmB;YACzC,MAAM,EAAE,MAAM,CAAC,IAAI;SACpB,CAAC,CAAC;QAEH,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAEzD,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,wBAAwB,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;YAC3F,OAAO,EAAE,SAAS;SACnB,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface SkillsConfig {
|
|
2
|
+
enabled: boolean;
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Workspace skills: contributes the workspace skills directory as a pi skill source.
|
|
6
|
+
* pi natively handles discovery, progressive disclosure, and /skill commands, so the
|
|
7
|
+
* extension only wires the source and exposes skill-bundled agent definitions through
|
|
8
|
+
* a delegate_to_agent tool.
|
|
9
|
+
*/
|
|
10
|
+
declare const _default: import("../api.ts").TachikomaExtension<SkillsConfig>;
|
|
11
|
+
export default _default;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { mkdir } from "node:fs/promises";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { Type } from "typebox";
|
|
4
|
+
import { defineExtension } from "../api.js";
|
|
5
|
+
import { discoverSkillAgents } from "./agents.js";
|
|
6
|
+
import { createDelegateTool } from "./delegate.js";
|
|
7
|
+
import { registerReload } from "./reload.js";
|
|
8
|
+
// Built-in authoring skills ship inside the repo's skills/ directory, three levels
|
|
9
|
+
// up from this module (src/extensions/skills → repo root).
|
|
10
|
+
const builtinSkillsDir = resolve(import.meta.dirname, "../../../skills");
|
|
11
|
+
/**
|
|
12
|
+
* Workspace skills: contributes the workspace skills directory as a pi skill source.
|
|
13
|
+
* pi natively handles discovery, progressive disclosure, and /skill commands, so the
|
|
14
|
+
* extension only wires the source and exposes skill-bundled agent definitions through
|
|
15
|
+
* a delegate_to_agent tool.
|
|
16
|
+
*/
|
|
17
|
+
export default defineExtension({
|
|
18
|
+
name: "skills",
|
|
19
|
+
configSchema: Type.Object({
|
|
20
|
+
enabled: Type.Boolean({ default: true }),
|
|
21
|
+
}),
|
|
22
|
+
setup(app) {
|
|
23
|
+
if (!app.extensionConfig.enabled) {
|
|
24
|
+
app.log.info("skills disabled by configuration");
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const skillsDir = app.workspace.resolve("skills");
|
|
28
|
+
app.bootstrap("ensure-skills-dir", async () => {
|
|
29
|
+
await mkdir(skillsDir, { recursive: true });
|
|
30
|
+
});
|
|
31
|
+
app.agent.use((pi) => {
|
|
32
|
+
pi.on("resources_discover", () => ({ skillPaths: [skillsDir, builtinSkillsDir] }));
|
|
33
|
+
registerReload(pi);
|
|
34
|
+
// Discovery runs per agent session, so new skill agents appear on the next
|
|
35
|
+
// session without a restart. No tool is advertised when no agents exist.
|
|
36
|
+
const discover = () => discoverSkillAgents(skillsDir, app.log);
|
|
37
|
+
if (discover().length > 0) {
|
|
38
|
+
pi.registerTool(createDelegateTool({ discover, runner: app.agent.side, log: app.log }));
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/skills/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAM7C,mFAAmF;AACnF,2DAA2D;AAC3D,MAAM,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;AAEzE;;;;;GAKG;AACH,eAAe,eAAe,CAAe;IAC3C,IAAI,EAAE,QAAQ;IAEd,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,kCAAkC,CAAC,CAAC;YACjD,OAAO;QACT,CAAC;QAED,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAElD,GAAG,CAAC,SAAS,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;YAC5C,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;QAEH,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE;YACnB,EAAE,CAAC,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,SAAS,EAAE,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC;YAEnF,cAAc,CAAC,EAAE,CAAC,CAAC;YAEnB,2EAA2E;YAC3E,yEAAyE;YACzE,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,mBAAmB,CAAC,SAAS,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;YAE/D,IAAI,QAAQ,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1B,EAAE,CAAC,YAAY,CAAC,kBAAkB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YAC1F,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
/**
|
|
3
|
+
* Mid-session resource reload, pi-style: a /reload command (reload must run in
|
|
4
|
+
* command context) plus a tool that queues it, so the agent can refresh skills
|
|
5
|
+
* itself when the user mentions adding or editing one. New sessions always
|
|
6
|
+
* rediscover skills regardless — this covers the live session.
|
|
7
|
+
*/
|
|
8
|
+
export declare const registerReload: (pi: ExtensionAPI) => void;
|