@treeseed/agent 0.1.2
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/Dockerfile +7 -0
- package/README.md +62 -0
- package/dist/agent-runtime.js +111 -0
- package/dist/agents/adapters/execution.js +90 -0
- package/dist/agents/adapters/mutations.js +30 -0
- package/dist/agents/adapters/notification.js +16 -0
- package/dist/agents/adapters/repository.js +61 -0
- package/dist/agents/adapters/research.js +25 -0
- package/dist/agents/adapters/verification.js +62 -0
- package/dist/agents/cli-tools.js +5 -0
- package/dist/agents/cli.js +77 -0
- package/dist/agents/content-store.js +1 -0
- package/dist/agents/contracts/messages.js +138 -0
- package/dist/agents/contracts/run.js +0 -0
- package/dist/agents/d1-store.js +1 -0
- package/dist/agents/frontmatter.js +1 -0
- package/dist/agents/git-runtime.js +1 -0
- package/dist/agents/index.js +5 -0
- package/dist/agents/kernel/agent-kernel.js +284 -0
- package/dist/agents/kernel/trigger-resolver.js +153 -0
- package/dist/agents/model-registry.js +1 -0
- package/dist/agents/registry-helper.js +14 -0
- package/dist/agents/registry.js +91 -0
- package/dist/agents/runtime-types.js +0 -0
- package/dist/agents/sdk-filters.js +1 -0
- package/dist/agents/sdk-types.js +1 -0
- package/dist/agents/sdk.js +1 -0
- package/dist/agents/spec-loader.js +53 -0
- package/dist/agents/spec-normalizer.js +257 -0
- package/dist/agents/spec-types.js +0 -0
- package/dist/agents/stores/cursor-store.js +1 -0
- package/dist/agents/stores/helpers.js +1 -0
- package/dist/agents/stores/lease-store.js +1 -0
- package/dist/agents/stores/message-store.js +1 -0
- package/dist/agents/stores/run-store.js +1 -0
- package/dist/agents/stores/subscription-store.js +1 -0
- package/dist/agents/testing/agents-smoke.js +32 -0
- package/dist/agents/testing/e2e-harness.js +435 -0
- package/dist/agents/wrangler-d1.js +1 -0
- package/dist/index.js +9 -0
- package/dist/scripts/assert-release-tag-version.d.ts +1 -0
- package/dist/scripts/assert-release-tag-version.js +20 -0
- package/dist/scripts/build-dist.d.ts +1 -0
- package/dist/scripts/build-dist.js +98 -0
- package/dist/scripts/package-tools.d.ts +1 -0
- package/dist/scripts/package-tools.js +7 -0
- package/dist/scripts/publish-package.d.ts +1 -0
- package/dist/scripts/publish-package.js +19 -0
- package/dist/scripts/release-verify.d.ts +1 -0
- package/dist/scripts/release-verify.js +143 -0
- package/dist/scripts/test-smoke.d.ts +1 -0
- package/dist/scripts/test-smoke.js +23 -0
- package/dist/scripts/treeseed-agents.d.ts +2 -0
- package/dist/scripts/treeseed-agents.js +13 -0
- package/dist/src/agent-runtime.d.ts +17 -0
- package/dist/src/agents/adapters/execution.d.ts +46 -0
- package/dist/src/agents/adapters/mutations.d.ts +22 -0
- package/dist/src/agents/adapters/notification.d.ts +11 -0
- package/dist/src/agents/adapters/repository.d.ts +28 -0
- package/dist/src/agents/adapters/research.d.ts +14 -0
- package/dist/src/agents/adapters/verification.d.ts +36 -0
- package/dist/src/agents/cli-tools.d.ts +1 -0
- package/dist/src/agents/cli.d.ts +6 -0
- package/dist/src/agents/content-store.d.ts +1 -0
- package/dist/src/agents/contracts/messages.d.ts +88 -0
- package/dist/src/agents/contracts/run.d.ts +20 -0
- package/dist/src/agents/d1-store.d.ts +1 -0
- package/dist/src/agents/frontmatter.d.ts +1 -0
- package/dist/src/agents/git-runtime.d.ts +1 -0
- package/dist/src/agents/index.d.ts +1 -0
- package/dist/src/agents/kernel/agent-kernel.d.ts +52 -0
- package/dist/src/agents/kernel/trigger-resolver.d.ts +18 -0
- package/dist/src/agents/model-registry.d.ts +1 -0
- package/dist/src/agents/registry-helper.d.ts +4 -0
- package/dist/src/agents/registry.d.ts +7 -0
- package/dist/src/agents/runtime-types.d.ts +117 -0
- package/dist/src/agents/sdk-filters.d.ts +1 -0
- package/dist/src/agents/sdk-types.d.ts +1 -0
- package/dist/src/agents/sdk.d.ts +1 -0
- package/dist/src/agents/spec-loader.d.ts +18 -0
- package/dist/src/agents/spec-normalizer.d.ts +2 -0
- package/dist/src/agents/spec-types.d.ts +64 -0
- package/dist/src/agents/stores/cursor-store.d.ts +1 -0
- package/dist/src/agents/stores/helpers.d.ts +1 -0
- package/dist/src/agents/stores/lease-store.d.ts +1 -0
- package/dist/src/agents/stores/message-store.d.ts +1 -0
- package/dist/src/agents/stores/run-store.d.ts +1 -0
- package/dist/src/agents/stores/subscription-store.d.ts +1 -0
- package/dist/src/agents/testing/agents-smoke.d.ts +1 -0
- package/dist/src/agents/testing/e2e-harness.d.ts +44 -0
- package/dist/src/agents/wrangler-d1.d.ts +1 -0
- package/dist/src/index.d.ts +3 -0
- package/package.json +54 -0
package/Dockerfile
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# `@treeseed/agent`
|
|
2
|
+
|
|
3
|
+
Treeseed agent service runtime package.
|
|
4
|
+
|
|
5
|
+
This package publishes the `treeseed-agents` CLI and the runtime exports needed to load, inspect, and execute TreeSeed agents in a Treeseed tenant repository.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Node `>=20`
|
|
10
|
+
- npm
|
|
11
|
+
- a Treeseed tenant repository for runtime commands such as `doctor` and `start`
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @treeseed/agent @treeseed/core @treeseed/sdk
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Build And Test
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install
|
|
23
|
+
npm run build
|
|
24
|
+
npm test
|
|
25
|
+
npm run release:verify
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`npm test` runs the package smoke test. `npm run release:verify` rebuilds the package, runs the smoke test, and verifies that the packed tarball installs cleanly with the published `treeseed-agents` binary.
|
|
29
|
+
|
|
30
|
+
## CLI
|
|
31
|
+
|
|
32
|
+
Run the CLI from a Treeseed tenant repository root, or set `TREESEED_TENANT_ROOT` to point at one.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
treeseed-agents doctor
|
|
36
|
+
treeseed-agents run-agent planner-agent
|
|
37
|
+
treeseed-agents start
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Available commands:
|
|
41
|
+
|
|
42
|
+
- `doctor`
|
|
43
|
+
- `run-agent <slug>`
|
|
44
|
+
- `drain-messages`
|
|
45
|
+
- `release-leases`
|
|
46
|
+
- `replay-message <id>`
|
|
47
|
+
- `start`
|
|
48
|
+
|
|
49
|
+
## Package Scripts
|
|
50
|
+
|
|
51
|
+
- `npm run setup`: install dependencies with `npm install`
|
|
52
|
+
- `npm run setup:ci`: install dependencies with `npm ci`
|
|
53
|
+
- `npm run build`: build the distributable package
|
|
54
|
+
- `npm test`: run the smoke test
|
|
55
|
+
- `npm run release:verify`: verify build, smoke test, and packed-install behavior
|
|
56
|
+
- `npm run release:check-tag -- <tag>`: validate plain semver tags like `0.1.1` against `package.json`
|
|
57
|
+
- `npm run release:publish`: publish to npm
|
|
58
|
+
|
|
59
|
+
## GitHub Actions
|
|
60
|
+
|
|
61
|
+
- `.github/workflows/ci.yml` runs `npm ci`, `npm run build`, `npm test`, and `npm run release:verify` on pushes and pull requests.
|
|
62
|
+
- `.github/workflows/publish.yml` runs the same verification steps before publishing on `*.*.*` version tags or manual dispatch.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { loadTreeseedPluginRuntime } from "@treeseed/core/plugins/runtime";
|
|
2
|
+
import {
|
|
3
|
+
CopilotExecutionAdapter,
|
|
4
|
+
ManualExecutionAdapter,
|
|
5
|
+
StubExecutionAdapter
|
|
6
|
+
} from "./agents/adapters/execution.js";
|
|
7
|
+
import { LocalBranchMutationAdapter } from "./agents/adapters/mutations.js";
|
|
8
|
+
import { StubNotificationAdapter } from "./agents/adapters/notification.js";
|
|
9
|
+
import { GitRepositoryInspectionAdapter, StubRepositoryInspectionAdapter } from "./agents/adapters/repository.js";
|
|
10
|
+
import { StubResearchAdapter } from "./agents/adapters/research.js";
|
|
11
|
+
import { LocalVerificationAdapter, StubVerificationAdapter } from "./agents/adapters/verification.js";
|
|
12
|
+
let cachedAgentRuntime = null;
|
|
13
|
+
function readPluginRecord(pluginEntry, key) {
|
|
14
|
+
const value = pluginEntry.plugin[key];
|
|
15
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
16
|
+
}
|
|
17
|
+
function assertUniqueProvider(registry, id, owner) {
|
|
18
|
+
if (registry.has(id)) {
|
|
19
|
+
throw new Error(`Treeseed plugin runtime found duplicate provider "${id}" from ${owner}.`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function collectAgentHandlersFromPlugin(pluginEntry, registry) {
|
|
23
|
+
const contributedHandlers = readPluginRecord(pluginEntry, "agentHandlers");
|
|
24
|
+
for (const [id, handler] of Object.entries(contributedHandlers)) {
|
|
25
|
+
assertUniqueProvider(registry, id, pluginEntry.package);
|
|
26
|
+
registry.set(id, handler);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function buildAgentRuntime() {
|
|
30
|
+
const runtime = loadTreeseedPluginRuntime();
|
|
31
|
+
const execution = /* @__PURE__ */ new Map([
|
|
32
|
+
["stub", () => new StubExecutionAdapter()],
|
|
33
|
+
["manual", () => new ManualExecutionAdapter()],
|
|
34
|
+
["copilot", () => new CopilotExecutionAdapter()]
|
|
35
|
+
]);
|
|
36
|
+
const mutation = /* @__PURE__ */ new Map([
|
|
37
|
+
["local_branch", (repoRoot) => new LocalBranchMutationAdapter(repoRoot)]
|
|
38
|
+
]);
|
|
39
|
+
const repository = /* @__PURE__ */ new Map([
|
|
40
|
+
["stub", () => new StubRepositoryInspectionAdapter()],
|
|
41
|
+
["git", () => new GitRepositoryInspectionAdapter()]
|
|
42
|
+
]);
|
|
43
|
+
const verification = /* @__PURE__ */ new Map([
|
|
44
|
+
["stub", () => new StubVerificationAdapter()],
|
|
45
|
+
["local", () => new LocalVerificationAdapter()]
|
|
46
|
+
]);
|
|
47
|
+
const notification = /* @__PURE__ */ new Map([["stub", () => new StubNotificationAdapter()]]);
|
|
48
|
+
const research = /* @__PURE__ */ new Map([["stub", () => new StubResearchAdapter()]]);
|
|
49
|
+
const handlers = /* @__PURE__ */ new Map();
|
|
50
|
+
for (const pluginEntry of runtime.plugins) {
|
|
51
|
+
const agentProviders = readPluginRecord(pluginEntry, "agentProviders");
|
|
52
|
+
for (const [id, factory] of Object.entries(agentProviders.execution ?? {})) {
|
|
53
|
+
assertUniqueProvider(execution, id, pluginEntry.package);
|
|
54
|
+
execution.set(id, factory);
|
|
55
|
+
}
|
|
56
|
+
for (const [id, factory] of Object.entries(agentProviders.mutation ?? {})) {
|
|
57
|
+
assertUniqueProvider(mutation, id, pluginEntry.package);
|
|
58
|
+
mutation.set(id, factory);
|
|
59
|
+
}
|
|
60
|
+
for (const [id, factory] of Object.entries(agentProviders.repository ?? {})) {
|
|
61
|
+
assertUniqueProvider(repository, id, pluginEntry.package);
|
|
62
|
+
repository.set(id, factory);
|
|
63
|
+
}
|
|
64
|
+
for (const [id, factory] of Object.entries(agentProviders.verification ?? {})) {
|
|
65
|
+
assertUniqueProvider(verification, id, pluginEntry.package);
|
|
66
|
+
verification.set(id, factory);
|
|
67
|
+
}
|
|
68
|
+
for (const [id, factory] of Object.entries(agentProviders.notification ?? {})) {
|
|
69
|
+
assertUniqueProvider(notification, id, pluginEntry.package);
|
|
70
|
+
notification.set(id, factory);
|
|
71
|
+
}
|
|
72
|
+
for (const [id, factory] of Object.entries(agentProviders.research ?? {})) {
|
|
73
|
+
assertUniqueProvider(research, id, pluginEntry.package);
|
|
74
|
+
research.set(id, factory);
|
|
75
|
+
}
|
|
76
|
+
collectAgentHandlersFromPlugin(pluginEntry, handlers);
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
providers: { execution, mutation, repository, verification, notification, research },
|
|
80
|
+
handlers
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function resolveAgentRuntimeProviders(repoRoot, selections) {
|
|
84
|
+
if (!cachedAgentRuntime) {
|
|
85
|
+
cachedAgentRuntime = buildAgentRuntime();
|
|
86
|
+
}
|
|
87
|
+
const executionFactory = cachedAgentRuntime.providers.execution.get(selections.execution);
|
|
88
|
+
const mutationFactory = cachedAgentRuntime.providers.mutation.get(selections.mutation);
|
|
89
|
+
const repositoryFactory = cachedAgentRuntime.providers.repository.get(selections.repository);
|
|
90
|
+
const verificationFactory = cachedAgentRuntime.providers.verification.get(selections.verification);
|
|
91
|
+
const notificationFactory = cachedAgentRuntime.providers.notification.get(selections.notification);
|
|
92
|
+
const researchFactory = cachedAgentRuntime.providers.research.get(selections.research);
|
|
93
|
+
if (!executionFactory) throw new Error(`Treeseed agent execution provider "${selections.execution}" is not registered.`);
|
|
94
|
+
if (!mutationFactory) throw new Error(`Treeseed agent mutation provider "${selections.mutation}" is not registered.`);
|
|
95
|
+
if (!repositoryFactory) throw new Error(`Treeseed agent repository provider "${selections.repository}" is not registered.`);
|
|
96
|
+
if (!verificationFactory) throw new Error(`Treeseed agent verification provider "${selections.verification}" is not registered.`);
|
|
97
|
+
if (!notificationFactory) throw new Error(`Treeseed agent notification provider "${selections.notification}" is not registered.`);
|
|
98
|
+
if (!researchFactory) throw new Error(`Treeseed agent research provider "${selections.research}" is not registered.`);
|
|
99
|
+
return {
|
|
100
|
+
execution: executionFactory(),
|
|
101
|
+
mutations: mutationFactory(repoRoot),
|
|
102
|
+
repository: repositoryFactory(),
|
|
103
|
+
verification: verificationFactory(),
|
|
104
|
+
notifications: notificationFactory(),
|
|
105
|
+
research: researchFactory(),
|
|
106
|
+
handlers: cachedAgentRuntime.handlers
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export {
|
|
110
|
+
resolveAgentRuntimeProviders
|
|
111
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
import { normalizeAgentCliOptions, buildCopilotAllowToolArgs } from "../cli-tools.js";
|
|
4
|
+
import { getTreeseedAgentProviderSelections } from "@treeseed/core/deploy/runtime";
|
|
5
|
+
const execFileAsync = promisify(execFile);
|
|
6
|
+
class StubExecutionAdapter {
|
|
7
|
+
async runTask(input) {
|
|
8
|
+
return {
|
|
9
|
+
status: "completed",
|
|
10
|
+
summary: `Stubbed Copilot execution for ${input.runId}.`,
|
|
11
|
+
stdout: [
|
|
12
|
+
"# Planned Task",
|
|
13
|
+
"",
|
|
14
|
+
"1. Inspect the requested architecture context.",
|
|
15
|
+
"2. Produce a safe local change artifact.",
|
|
16
|
+
"3. Summarize the implementation intent.",
|
|
17
|
+
"",
|
|
18
|
+
`Prompt digest: ${input.prompt.slice(0, 240)}`
|
|
19
|
+
].join("\n"),
|
|
20
|
+
stderr: ""
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
class CopilotExecutionAdapter {
|
|
25
|
+
async runTask(input) {
|
|
26
|
+
const cli = normalizeAgentCliOptions(input.agent.cli);
|
|
27
|
+
const args = ["copilot", "-p", input.prompt];
|
|
28
|
+
if (cli.model) {
|
|
29
|
+
args.push("--model", cli.model);
|
|
30
|
+
}
|
|
31
|
+
args.push(...buildCopilotAllowToolArgs(cli.allowTools));
|
|
32
|
+
args.push(...cli.additionalArgs ?? []);
|
|
33
|
+
try {
|
|
34
|
+
const { stdout, stderr } = await execFileAsync("gh", args, {
|
|
35
|
+
cwd: process.cwd(),
|
|
36
|
+
env: process.env,
|
|
37
|
+
maxBuffer: 10 * 1024 * 1024
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
status: "completed",
|
|
41
|
+
summary: "Copilot task completed.",
|
|
42
|
+
stdout,
|
|
43
|
+
stderr
|
|
44
|
+
};
|
|
45
|
+
} catch (error) {
|
|
46
|
+
const stderr = error && typeof error === "object" && "stderr" in error ? String(error.stderr ?? "") : error instanceof Error ? error.message : String(error);
|
|
47
|
+
return {
|
|
48
|
+
status: "failed",
|
|
49
|
+
summary: "Copilot task failed.",
|
|
50
|
+
stdout: "",
|
|
51
|
+
stderr
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
class ManualExecutionAdapter {
|
|
57
|
+
async runTask(input) {
|
|
58
|
+
return {
|
|
59
|
+
status: "completed",
|
|
60
|
+
summary: `Manual execution mode is enabled for ${input.runId}.`,
|
|
61
|
+
stdout: [
|
|
62
|
+
"# Manual Execution Required",
|
|
63
|
+
"",
|
|
64
|
+
"This agent run is configured for manual execution.",
|
|
65
|
+
"Review the prompt below and complete the work outside the automated adapter.",
|
|
66
|
+
"",
|
|
67
|
+
input.prompt
|
|
68
|
+
].join("\n"),
|
|
69
|
+
stderr: ""
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function createExecutionAdapter() {
|
|
74
|
+
const configuredMode = String(
|
|
75
|
+
process.env.TREESEED_AGENT_EXECUTION_PROVIDER ?? getTreeseedAgentProviderSelections().execution
|
|
76
|
+
).toLowerCase();
|
|
77
|
+
if (configuredMode === "manual") {
|
|
78
|
+
return new ManualExecutionAdapter();
|
|
79
|
+
}
|
|
80
|
+
if (configuredMode !== "copilot") {
|
|
81
|
+
return new StubExecutionAdapter();
|
|
82
|
+
}
|
|
83
|
+
return new CopilotExecutionAdapter();
|
|
84
|
+
}
|
|
85
|
+
export {
|
|
86
|
+
CopilotExecutionAdapter,
|
|
87
|
+
ManualExecutionAdapter,
|
|
88
|
+
StubExecutionAdapter,
|
|
89
|
+
createExecutionAdapter
|
|
90
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { GitRuntime } from "../git-runtime.js";
|
|
4
|
+
class LocalBranchMutationAdapter {
|
|
5
|
+
git;
|
|
6
|
+
constructor(repoRoot) {
|
|
7
|
+
this.git = new GitRuntime(
|
|
8
|
+
repoRoot,
|
|
9
|
+
process.env.TREESEED_AGENT_DISABLE_GIT === "true"
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
async writeArtifact(input) {
|
|
13
|
+
const branchName = `${input.agent.execution.branchPrefix}/${input.runId}`;
|
|
14
|
+
const worktreePath = await this.git.ensureWorktree(branchName);
|
|
15
|
+
const filePath = path.join(worktreePath, input.relativePath);
|
|
16
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
17
|
+
await writeFile(filePath, input.content, "utf8");
|
|
18
|
+
const git = await this.git.commitFileChange(filePath, branchName, input.commitMessage);
|
|
19
|
+
return {
|
|
20
|
+
branchName: git.branchName,
|
|
21
|
+
commitMessage: git.commitMessage,
|
|
22
|
+
worktreePath: git.worktreePath,
|
|
23
|
+
commitSha: git.commitSha,
|
|
24
|
+
changedPaths: git.changedPaths
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
LocalBranchMutationAdapter
|
|
30
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class StubNotificationAdapter {
|
|
2
|
+
async deliver(input) {
|
|
3
|
+
return {
|
|
4
|
+
status: input.recipients.length ? "completed" : "waiting",
|
|
5
|
+
summary: input.recipients.length ? `Prepared ${input.recipients.length} notification(s).` : "No recipients available for notification.",
|
|
6
|
+
deliveredCount: input.recipients.length
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function createNotificationAdapter() {
|
|
11
|
+
return new StubNotificationAdapter();
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
StubNotificationAdapter,
|
|
15
|
+
createNotificationAdapter
|
|
16
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
import { getTreeseedAgentProviderSelections } from "@treeseed/core/deploy/runtime";
|
|
4
|
+
const execFileAsync = promisify(execFile);
|
|
5
|
+
class StubRepositoryInspectionAdapter {
|
|
6
|
+
async inspectBranch(input) {
|
|
7
|
+
return {
|
|
8
|
+
branchName: input.branchName,
|
|
9
|
+
changedPaths: [],
|
|
10
|
+
commitSha: null,
|
|
11
|
+
summary: input.branchName ? `Stub repository inspection for ${input.branchName}.` : "No branch to inspect."
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
class GitRepositoryInspectionAdapter {
|
|
16
|
+
async inspectBranch(input) {
|
|
17
|
+
if (!input.branchName) {
|
|
18
|
+
return {
|
|
19
|
+
branchName: null,
|
|
20
|
+
changedPaths: [],
|
|
21
|
+
commitSha: null,
|
|
22
|
+
summary: "No branch to inspect."
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const { stdout: changedStdout } = await execFileAsync(
|
|
27
|
+
"git",
|
|
28
|
+
["diff", "--name-only", "HEAD~1..HEAD"],
|
|
29
|
+
{ cwd: input.repoRoot, env: process.env }
|
|
30
|
+
);
|
|
31
|
+
const { stdout: shaStdout } = await execFileAsync("git", ["rev-parse", "HEAD"], {
|
|
32
|
+
cwd: input.repoRoot,
|
|
33
|
+
env: process.env
|
|
34
|
+
});
|
|
35
|
+
const changedPaths = changedStdout.split("\n").map((entry) => entry.trim()).filter(Boolean);
|
|
36
|
+
return {
|
|
37
|
+
branchName: input.branchName,
|
|
38
|
+
changedPaths,
|
|
39
|
+
commitSha: shaStdout.trim() || null,
|
|
40
|
+
summary: `Inspected ${changedPaths.length} changed path(s) on ${input.branchName}.`
|
|
41
|
+
};
|
|
42
|
+
} catch {
|
|
43
|
+
return {
|
|
44
|
+
branchName: input.branchName,
|
|
45
|
+
changedPaths: [],
|
|
46
|
+
commitSha: null,
|
|
47
|
+
summary: `Unable to inspect branch ${input.branchName}.`
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function createRepositoryInspectionAdapter() {
|
|
53
|
+
return String(
|
|
54
|
+
process.env.TREESEED_AGENT_REPOSITORY_PROVIDER ?? getTreeseedAgentProviderSelections().repository
|
|
55
|
+
).toLowerCase() !== "git" ? new StubRepositoryInspectionAdapter() : new GitRepositoryInspectionAdapter();
|
|
56
|
+
}
|
|
57
|
+
export {
|
|
58
|
+
GitRepositoryInspectionAdapter,
|
|
59
|
+
StubRepositoryInspectionAdapter,
|
|
60
|
+
createRepositoryInspectionAdapter
|
|
61
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
class StubResearchAdapter {
|
|
2
|
+
async research(input) {
|
|
3
|
+
return {
|
|
4
|
+
status: "completed",
|
|
5
|
+
summary: `Research prepared for ${input.questionId}.`,
|
|
6
|
+
markdown: [
|
|
7
|
+
"# Research Summary",
|
|
8
|
+
"",
|
|
9
|
+
`Question: ${input.questionId}`,
|
|
10
|
+
`Reason: ${input.reason ?? "not provided"}`,
|
|
11
|
+
`Run: ${input.runId}`,
|
|
12
|
+
"",
|
|
13
|
+
"This is a stub research summary produced by the runtime adapter."
|
|
14
|
+
].join("\n"),
|
|
15
|
+
sources: []
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function createResearchAdapter() {
|
|
20
|
+
return new StubResearchAdapter();
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
StubResearchAdapter,
|
|
24
|
+
createResearchAdapter
|
|
25
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
import { getTreeseedAgentProviderSelections } from "@treeseed/core/deploy/runtime";
|
|
4
|
+
const execFileAsync = promisify(execFile);
|
|
5
|
+
class StubVerificationAdapter {
|
|
6
|
+
async runChecks(input) {
|
|
7
|
+
return {
|
|
8
|
+
status: "completed",
|
|
9
|
+
summary: input.commands.length ? `Stub verification completed for ${input.runId}.` : "No verification commands configured.",
|
|
10
|
+
stdout: input.commands.join("\n"),
|
|
11
|
+
stderr: ""
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
class LocalVerificationAdapter {
|
|
16
|
+
async runChecks(input) {
|
|
17
|
+
if (!input.commands.length) {
|
|
18
|
+
return {
|
|
19
|
+
status: "waiting",
|
|
20
|
+
summary: "No verification commands configured.",
|
|
21
|
+
stdout: "",
|
|
22
|
+
stderr: ""
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const stdoutChunks = [];
|
|
26
|
+
const stderrChunks = [];
|
|
27
|
+
for (const command of input.commands) {
|
|
28
|
+
try {
|
|
29
|
+
const { stdout, stderr } = await execFileAsync("/bin/bash", ["-lc", command], {
|
|
30
|
+
env: process.env,
|
|
31
|
+
maxBuffer: 10 * 1024 * 1024
|
|
32
|
+
});
|
|
33
|
+
stdoutChunks.push(stdout);
|
|
34
|
+
stderrChunks.push(stderr);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
return {
|
|
37
|
+
status: "failed",
|
|
38
|
+
summary: `Verification command failed: ${command}`,
|
|
39
|
+
stdout: stdoutChunks.join("\n"),
|
|
40
|
+
stderr: error && typeof error === "object" && "stderr" in error ? String(error.stderr ?? "") : String(error),
|
|
41
|
+
errorCategory: "execution_error"
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
status: "completed",
|
|
47
|
+
summary: `Verification completed for ${input.commands.length} command(s).`,
|
|
48
|
+
stdout: stdoutChunks.join("\n"),
|
|
49
|
+
stderr: stderrChunks.join("\n")
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function createVerificationAdapter() {
|
|
54
|
+
return String(
|
|
55
|
+
process.env.TREESEED_AGENT_VERIFICATION_PROVIDER ?? getTreeseedAgentProviderSelections().verification
|
|
56
|
+
).toLowerCase() !== "local" ? new StubVerificationAdapter() : new LocalVerificationAdapter();
|
|
57
|
+
}
|
|
58
|
+
export {
|
|
59
|
+
LocalVerificationAdapter,
|
|
60
|
+
StubVerificationAdapter,
|
|
61
|
+
createVerificationAdapter
|
|
62
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
function parseArgs(argv) {
|
|
2
|
+
const [, , command = "doctor", ...rest] = argv;
|
|
3
|
+
return {
|
|
4
|
+
command,
|
|
5
|
+
args: rest
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
function renderHelp() {
|
|
9
|
+
return [
|
|
10
|
+
"treeseed-agents <command>",
|
|
11
|
+
"",
|
|
12
|
+
"Commands:",
|
|
13
|
+
" doctor",
|
|
14
|
+
" run-agent <slug>",
|
|
15
|
+
" drain-messages",
|
|
16
|
+
" release-leases",
|
|
17
|
+
" replay-message <id>",
|
|
18
|
+
" start"
|
|
19
|
+
].join("\n");
|
|
20
|
+
}
|
|
21
|
+
async function main() {
|
|
22
|
+
const { command, args } = parseArgs(process.argv);
|
|
23
|
+
if (command === "--help" || command === "-h" || command === "help") {
|
|
24
|
+
console.log(renderHelp());
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const [{ AgentKernel }, { AgentSdk }] = await Promise.all([
|
|
28
|
+
import("./kernel/agent-kernel.js"),
|
|
29
|
+
import("./sdk.js")
|
|
30
|
+
]);
|
|
31
|
+
const repoRoot = process.cwd();
|
|
32
|
+
const sdk = AgentSdk.createLocal({
|
|
33
|
+
repoRoot,
|
|
34
|
+
databaseName: process.env.TREESEED_AGENT_D1_DATABASE ?? "karyon-docs-site-data",
|
|
35
|
+
persistTo: process.env.TREESEED_AGENT_D1_PERSIST_TO ?? void 0
|
|
36
|
+
});
|
|
37
|
+
const kernel = new AgentKernel(sdk, repoRoot);
|
|
38
|
+
if (command === "doctor") {
|
|
39
|
+
console.log(JSON.stringify({ ok: true, command, ...await kernel.doctor() }, null, 2));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (command === "run-agent") {
|
|
43
|
+
console.log(JSON.stringify({ ok: true, command, slug: args[0], result: await kernel.runAgent(args[0]) }, null, 2));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (command === "drain-messages") {
|
|
47
|
+
console.log(JSON.stringify({ ok: true, command, results: await kernel.drainMessages() }, null, 2));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (command === "release-leases") {
|
|
51
|
+
console.log(JSON.stringify({ ok: true, command, result: await kernel.releaseLeases() }, null, 2));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (command === "replay-message") {
|
|
55
|
+
console.log(JSON.stringify({ ok: true, command, result: await kernel.replayMessage(Number(args[0])) }, null, 2));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (command === "start") {
|
|
59
|
+
console.log(JSON.stringify({ ok: true, command, status: "starting" }, null, 2));
|
|
60
|
+
await kernel.start();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
throw new Error(`Unknown Treeseed command "${command}".`);
|
|
64
|
+
}
|
|
65
|
+
main().catch((error) => {
|
|
66
|
+
console.error(
|
|
67
|
+
JSON.stringify(
|
|
68
|
+
{
|
|
69
|
+
ok: false,
|
|
70
|
+
error: error instanceof Error ? error.message : String(error)
|
|
71
|
+
},
|
|
72
|
+
null,
|
|
73
|
+
2
|
|
74
|
+
)
|
|
75
|
+
);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "@treeseed/sdk/content-store";
|