feat: add TypeScript support and shared types
- Added TypeScript configuration file (tsconfig.json) with strict settings. - Introduced devDependencies for TypeScript in package.json. - Added scripts for type checking and watching for changes. - Created a new types file (lib/types.ts) defining shared types for the DevClaw plugin.
This commit is contained in:
@@ -4,13 +4,16 @@
|
||||
* Creates a new agent (optional), configures model tiers,
|
||||
* and writes workspace files (AGENTS.md, HEARTBEAT.md, roles, memory).
|
||||
*/
|
||||
import type { OpenClawPluginApi, OpenClawPluginToolContext } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { jsonResult } from "openclaw/plugin-sdk";
|
||||
import type { ToolContext } from "../types.js";
|
||||
import { runSetup } from "../setup.js";
|
||||
import { ALL_TIERS, DEFAULT_MODELS, type Tier } from "../tiers.js";
|
||||
|
||||
export function createSetupTool(api: OpenClawPluginApi) {
|
||||
return (ctx: OpenClawPluginToolContext) => ({
|
||||
return (ctx: ToolContext) => ({
|
||||
name: "devclaw_setup",
|
||||
label: "DevClaw Setup",
|
||||
description: `Set up DevClaw in an agent's workspace. Creates AGENTS.md, HEARTBEAT.md, role templates, memory/projects.json, and writes model tier config to openclaw.json. Optionally creates a new agent. Backs up existing files before overwriting.`,
|
||||
parameters: {
|
||||
type: "object",
|
||||
@@ -69,16 +72,11 @@ export function createSetupTool(api: OpenClawPluginApi) {
|
||||
` 3. Create your first issue and pick it up`,
|
||||
);
|
||||
|
||||
return {
|
||||
content: [{
|
||||
type: "text" as const,
|
||||
text: JSON.stringify({
|
||||
success: true,
|
||||
...result,
|
||||
summary: lines.join("\n"),
|
||||
}, null, 2),
|
||||
}],
|
||||
};
|
||||
return jsonResult({
|
||||
success: true,
|
||||
...result,
|
||||
summary: lines.join("\n"),
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
*
|
||||
* Replaces the manual steps of running glab/gh label create + editing projects.json.
|
||||
*/
|
||||
import type { OpenClawPluginApi, OpenClawPluginToolContext } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { jsonResult } from "openclaw/plugin-sdk";
|
||||
import type { ToolContext } from "../types.js";
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { readProjects, writeProjects, emptyWorkerState } from "../projects.js";
|
||||
@@ -67,8 +69,9 @@ async function scaffoldRoleFiles(workspaceDir: string, projectName: string): Pro
|
||||
}
|
||||
|
||||
export function createProjectRegisterTool(api: OpenClawPluginApi) {
|
||||
return (ctx: OpenClawPluginToolContext) => ({
|
||||
return (ctx: ToolContext) => ({
|
||||
name: "project_register",
|
||||
label: "Project Register",
|
||||
description: `Register a new project with DevClaw. Creates all required state labels (idempotent) and adds the project to projects.json. One-time setup per project. Auto-detects GitHub/GitLab from git remote.`,
|
||||
parameters: {
|
||||
type: "object",
|
||||
@@ -186,22 +189,17 @@ export function createProjectRegisterTool(api: OpenClawPluginApi) {
|
||||
const rolesNote = rolesCreated ? " Role files scaffolded." : "";
|
||||
const announcement = `📋 Project "${name}" registered for group ${groupName}. Labels created.${rolesNote} Ready for tasks.`;
|
||||
|
||||
return {
|
||||
content: [{
|
||||
type: "text" as const,
|
||||
text: JSON.stringify({
|
||||
success: true,
|
||||
project: name,
|
||||
groupId,
|
||||
repo,
|
||||
baseBranch,
|
||||
deployBranch,
|
||||
labelsCreated: 8,
|
||||
rolesScaffolded: rolesCreated,
|
||||
announcement,
|
||||
}, null, 2),
|
||||
}],
|
||||
};
|
||||
return jsonResult({
|
||||
success: true,
|
||||
project: name,
|
||||
groupId,
|
||||
repo,
|
||||
baseBranch,
|
||||
deployBranch,
|
||||
labelsCreated: 8,
|
||||
rolesScaffolded: rolesCreated,
|
||||
announcement,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,14 +3,17 @@
|
||||
*
|
||||
* Replaces manual GitLab scanning in HEARTBEAT.md.
|
||||
*/
|
||||
import type { OpenClawPluginApi, OpenClawPluginToolContext } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { jsonResult } from "openclaw/plugin-sdk";
|
||||
import type { ToolContext } from "../types.js";
|
||||
import { readProjects, getProject } from "../projects.js";
|
||||
import { listIssuesByLabel, resolveRepoPath, type StateLabel } from "../gitlab.js";
|
||||
import { log as auditLog } from "../audit.js";
|
||||
|
||||
export function createQueueStatusTool(api: OpenClawPluginApi) {
|
||||
return (ctx: OpenClawPluginToolContext) => ({
|
||||
return (ctx: ToolContext) => ({
|
||||
name: "queue_status",
|
||||
label: "Queue Status",
|
||||
description: `Show task queue counts and worker status for all projects (or a specific project). Returns To Improve, To Test, To Do issue counts and active DEV/QA session state.`,
|
||||
parameters: {
|
||||
type: "object",
|
||||
@@ -98,14 +101,7 @@ export function createQueueStatusTool(api: OpenClawPluginApi) {
|
||||
),
|
||||
});
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text" as const,
|
||||
text: JSON.stringify({ projects }, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
return jsonResult({ projects });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,14 +4,17 @@
|
||||
* Detects zombie sessions (active=true but session dead) and stale workers.
|
||||
* Checks the sessions map for each worker's current model.
|
||||
*/
|
||||
import type { OpenClawPluginApi, OpenClawPluginToolContext } from "openclaw/plugin-sdk";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { jsonResult } from "openclaw/plugin-sdk";
|
||||
import type { ToolContext } from "../types.js";
|
||||
import { readProjects, updateWorker, getSessionForModel } from "../projects.js";
|
||||
import { transitionLabel, resolveRepoPath, type StateLabel } from "../gitlab.js";
|
||||
import { log as auditLog } from "../audit.js";
|
||||
|
||||
export function createSessionHealthTool(api: OpenClawPluginApi) {
|
||||
return (ctx: OpenClawPluginToolContext) => ({
|
||||
return (ctx: ToolContext) => ({
|
||||
name: "session_health",
|
||||
label: "Session Health",
|
||||
description: `Check session state consistency across all projects. Detects: active workers with no session in their sessions map, stale workers (>2 hours), and state mismatches. With autoFix=true, clears zombie states and reverts GitLab labels. Pass activeSessions (from sessions_list) so the tool can verify liveness.`,
|
||||
parameters: {
|
||||
type: "object",
|
||||
@@ -189,9 +192,7 @@ export function createSessionHealthTool(api: OpenClawPluginApi) {
|
||||
: undefined,
|
||||
};
|
||||
|
||||
return {
|
||||
content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
|
||||
};
|
||||
return jsonResult(result);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,45 +8,59 @@
|
||||
* - DEV "done" → automatically dispatches QA (qa tier)
|
||||
* - QA "fail" → automatically dispatches DEV fix (reuses previous DEV tier)
|
||||
*/
|
||||
import type { OpenClawPluginApi, OpenClawPluginToolContext } from "openclaw/plugin-sdk";
|
||||
import {
|
||||
readProjects,
|
||||
getProject,
|
||||
getWorker,
|
||||
getSessionForModel,
|
||||
deactivateWorker,
|
||||
} from "../projects.js";
|
||||
import {
|
||||
getIssue,
|
||||
transitionLabel,
|
||||
closeIssue,
|
||||
reopenIssue,
|
||||
resolveRepoPath,
|
||||
type StateLabel,
|
||||
} from "../gitlab.js";
|
||||
import { log as auditLog } from "../audit.js";
|
||||
import { dispatchTask } from "../dispatch.js";
|
||||
import { execFile } from "node:child_process";
|
||||
import { promisify } from "node:util";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { jsonResult } from "openclaw/plugin-sdk";
|
||||
import { log as auditLog } from "../audit.js";
|
||||
import { dispatchTask } from "../dispatch.js";
|
||||
import {
|
||||
closeIssue,
|
||||
getIssue,
|
||||
reopenIssue,
|
||||
resolveRepoPath,
|
||||
transitionLabel,
|
||||
type StateLabel,
|
||||
} from "../gitlab.js";
|
||||
import {
|
||||
deactivateWorker,
|
||||
getProject,
|
||||
getSessionForModel,
|
||||
getWorker,
|
||||
readProjects,
|
||||
} from "../projects.js";
|
||||
import type { ToolContext } from "../types.js";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
export function createTaskCompleteTool(api: OpenClawPluginApi) {
|
||||
return (ctx: OpenClawPluginToolContext) => ({
|
||||
return (ctx: ToolContext) => ({
|
||||
name: "task_complete",
|
||||
label: "Task Complete",
|
||||
description: `Complete a task: DEV done, QA pass, QA fail, or QA refine. Atomically handles: label transition, projects.json update, issue close/reopen, and audit logging. If the project has autoChain enabled, automatically dispatches the next step (DEV done → QA, QA fail → DEV fix).`,
|
||||
parameters: {
|
||||
type: "object",
|
||||
required: ["role", "result", "projectGroupId"],
|
||||
properties: {
|
||||
role: { type: "string", enum: ["dev", "qa"], description: "Worker role completing the task" },
|
||||
role: {
|
||||
type: "string",
|
||||
enum: ["dev", "qa"],
|
||||
description: "Worker role completing the task",
|
||||
},
|
||||
result: {
|
||||
type: "string",
|
||||
enum: ["done", "pass", "fail", "refine"],
|
||||
description: 'Completion result: "done" (DEV finished), "pass" (QA approved), "fail" (QA found issues), "refine" (needs human input)',
|
||||
description:
|
||||
'Completion result: "done" (DEV finished), "pass" (QA approved), "fail" (QA found issues), "refine" (needs human input)',
|
||||
},
|
||||
projectGroupId: {
|
||||
type: "string",
|
||||
description: "Telegram group ID (key in projects.json)",
|
||||
},
|
||||
summary: {
|
||||
type: "string",
|
||||
description: "Brief summary for Telegram announcement",
|
||||
},
|
||||
projectGroupId: { type: "string", description: "Telegram group ID (key in projects.json)" },
|
||||
summary: { type: "string", description: "Brief summary for Telegram announcement" },
|
||||
},
|
||||
},
|
||||
|
||||
@@ -63,10 +77,14 @@ export function createTaskCompleteTool(api: OpenClawPluginApi) {
|
||||
|
||||
// Validate result matches role
|
||||
if (role === "dev" && result !== "done") {
|
||||
throw new Error(`DEV can only complete with result "done", got "${result}"`);
|
||||
throw new Error(
|
||||
`DEV can only complete with result "done", got "${result}"`,
|
||||
);
|
||||
}
|
||||
if (role === "qa" && result === "done") {
|
||||
throw new Error(`QA cannot use result "done". Use "pass", "fail", or "refine".`);
|
||||
throw new Error(
|
||||
`QA cannot use result "done". Use "pass", "fail", or "refine".`,
|
||||
);
|
||||
}
|
||||
|
||||
// Resolve project
|
||||
@@ -83,14 +101,20 @@ export function createTaskCompleteTool(api: OpenClawPluginApi) {
|
||||
);
|
||||
}
|
||||
|
||||
const issueId = worker.issueId ? Number(worker.issueId.split(",")[0]) : null;
|
||||
const issueId = worker.issueId
|
||||
? Number(worker.issueId.split(",")[0])
|
||||
: null;
|
||||
if (!issueId) {
|
||||
throw new Error(`No issueId found for active ${role.toUpperCase()} worker on ${project.name}`);
|
||||
throw new Error(
|
||||
`No issueId found for active ${role.toUpperCase()} worker on ${project.name}`,
|
||||
);
|
||||
}
|
||||
|
||||
const repoPath = resolveRepoPath(project.repo);
|
||||
const glabOpts = {
|
||||
glabPath: (api.pluginConfig as Record<string, unknown>)?.glabPath as string | undefined,
|
||||
glabPath: (api.pluginConfig as Record<string, unknown>)?.glabPath as
|
||||
| string
|
||||
| undefined,
|
||||
repoPath,
|
||||
};
|
||||
|
||||
@@ -106,7 +130,10 @@ export function createTaskCompleteTool(api: OpenClawPluginApi) {
|
||||
// === DEV DONE ===
|
||||
if (role === "dev" && result === "done") {
|
||||
try {
|
||||
await execFileAsync("git", ["pull"], { cwd: repoPath, timeout: 30_000 });
|
||||
await execFileAsync("git", ["pull"], {
|
||||
cwd: repoPath,
|
||||
timeout: 30_000,
|
||||
});
|
||||
output.gitPull = "success";
|
||||
} catch (err) {
|
||||
output.gitPull = `warning: ${(err as Error).message}`;
|
||||
@@ -120,7 +147,9 @@ export function createTaskCompleteTool(api: OpenClawPluginApi) {
|
||||
|
||||
if (project.autoChain) {
|
||||
try {
|
||||
const pluginConfig = api.pluginConfig as Record<string, unknown> | undefined;
|
||||
const pluginConfig = api.pluginConfig as
|
||||
| Record<string, unknown>
|
||||
| undefined;
|
||||
const issue = await getIssue(issueId, glabOpts);
|
||||
const chainResult = await dispatchTask({
|
||||
workspaceDir,
|
||||
@@ -136,7 +165,12 @@ export function createTaskCompleteTool(api: OpenClawPluginApi) {
|
||||
fromLabel: "To Test",
|
||||
toLabel: "Testing",
|
||||
transitionLabel: (id, from, to) =>
|
||||
transitionLabel(id, from as StateLabel, to as StateLabel, glabOpts),
|
||||
transitionLabel(
|
||||
id,
|
||||
from as StateLabel,
|
||||
to as StateLabel,
|
||||
glabOpts,
|
||||
),
|
||||
pluginConfig,
|
||||
});
|
||||
output.autoChain = {
|
||||
@@ -147,7 +181,10 @@ export function createTaskCompleteTool(api: OpenClawPluginApi) {
|
||||
announcement: chainResult.announcement,
|
||||
};
|
||||
} catch (err) {
|
||||
output.autoChain = { dispatched: false, error: (err as Error).message };
|
||||
output.autoChain = {
|
||||
dispatched: false,
|
||||
error: (err as Error).message,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
output.nextAction = "qa_pickup";
|
||||
@@ -173,7 +210,9 @@ export function createTaskCompleteTool(api: OpenClawPluginApi) {
|
||||
|
||||
const devWorker = getWorker(project, "dev");
|
||||
const devModel = devWorker.model;
|
||||
const devSessionKey = devModel ? getSessionForModel(devWorker, devModel) : null;
|
||||
const devSessionKey = devModel
|
||||
? getSessionForModel(devWorker, devModel)
|
||||
: null;
|
||||
|
||||
output.labelTransition = "Testing → To Improve";
|
||||
output.issueReopened = true;
|
||||
@@ -183,7 +222,9 @@ export function createTaskCompleteTool(api: OpenClawPluginApi) {
|
||||
|
||||
if (project.autoChain && devModel) {
|
||||
try {
|
||||
const pluginConfig = api.pluginConfig as Record<string, unknown> | undefined;
|
||||
const pluginConfig = api.pluginConfig as
|
||||
| Record<string, unknown>
|
||||
| undefined;
|
||||
const issue = await getIssue(issueId, glabOpts);
|
||||
const chainResult = await dispatchTask({
|
||||
workspaceDir,
|
||||
@@ -199,7 +240,12 @@ export function createTaskCompleteTool(api: OpenClawPluginApi) {
|
||||
fromLabel: "To Improve",
|
||||
toLabel: "Doing",
|
||||
transitionLabel: (id, from, to) =>
|
||||
transitionLabel(id, from as StateLabel, to as StateLabel, glabOpts),
|
||||
transitionLabel(
|
||||
id,
|
||||
from as StateLabel,
|
||||
to as StateLabel,
|
||||
glabOpts,
|
||||
),
|
||||
pluginConfig,
|
||||
});
|
||||
output.autoChain = {
|
||||
@@ -210,7 +256,10 @@ export function createTaskCompleteTool(api: OpenClawPluginApi) {
|
||||
announcement: chainResult.announcement,
|
||||
};
|
||||
} catch (err) {
|
||||
output.autoChain = { dispatched: false, error: (err as Error).message };
|
||||
output.autoChain = {
|
||||
dispatched: false,
|
||||
error: (err as Error).message,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
output.nextAction = "dev_fix";
|
||||
@@ -238,9 +287,7 @@ export function createTaskCompleteTool(api: OpenClawPluginApi) {
|
||||
autoChain: output.autoChain ?? null,
|
||||
});
|
||||
|
||||
return {
|
||||
content: [{ type: "text" as const, text: JSON.stringify(output, null, 2) }],
|
||||
};
|
||||
return jsonResult(output);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,8 +9,11 @@
|
||||
* - A sub-agent finds a bug and needs to file a follow-up issue
|
||||
* - Breaking down an epic into smaller tasks
|
||||
*/
|
||||
import type { OpenClawPluginApi, OpenClawPluginToolContext } from "openclaw/plugin-sdk";
|
||||
import { readProjects, resolveRepoPath } from "../projects.js";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { jsonResult } from "openclaw/plugin-sdk";
|
||||
import type { ToolContext } from "../types.js";
|
||||
import { readProjects } from "../projects.js";
|
||||
import { resolveRepoPath } from "../gitlab.js";
|
||||
import { createProvider } from "../providers/index.js";
|
||||
import { log as auditLog } from "../audit.js";
|
||||
import type { StateLabel } from "../issue-provider.js";
|
||||
@@ -27,8 +30,9 @@ const STATE_LABELS: StateLabel[] = [
|
||||
];
|
||||
|
||||
export function createTaskCreateTool(api: OpenClawPluginApi) {
|
||||
return (ctx: OpenClawPluginToolContext) => ({
|
||||
return (ctx: ToolContext) => ({
|
||||
name: "task_create",
|
||||
label: "Task Create",
|
||||
description: `Create a new task (issue) in the project's issue tracker. Use this to file bugs, features, or tasks from chat.
|
||||
|
||||
Examples:
|
||||
@@ -132,12 +136,7 @@ The issue is created with a state label (defaults to "Planning"). Returns the cr
|
||||
: `📋 Created #${issue.iid}: "${title}" (${label}).${hasBody ? " With detailed description." : ""} Ready for pickup when needed.`,
|
||||
};
|
||||
|
||||
return {
|
||||
content: [{
|
||||
type: "text" as const,
|
||||
text: JSON.stringify(result, null, 2),
|
||||
}],
|
||||
};
|
||||
return jsonResult(result);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,35 +8,44 @@
|
||||
* Model selection is LLM-based: the orchestrator passes a `model` param.
|
||||
* A keyword heuristic is used as fallback if no model is specified.
|
||||
*/
|
||||
import type { OpenClawPluginApi, OpenClawPluginToolContext } from "openclaw/plugin-sdk";
|
||||
import { readProjects, getProject, getWorker } from "../projects.js";
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { jsonResult } from "openclaw/plugin-sdk";
|
||||
import { dispatchTask } from "../dispatch.js";
|
||||
import {
|
||||
getIssue,
|
||||
getCurrentStateLabel,
|
||||
transitionLabel,
|
||||
getIssue,
|
||||
resolveRepoPath,
|
||||
transitionLabel,
|
||||
type StateLabel,
|
||||
} from "../gitlab.js";
|
||||
import { selectModel } from "../model-selector.js";
|
||||
import { dispatchTask } from "../dispatch.js";
|
||||
import { getProject, getWorker, readProjects } from "../projects.js";
|
||||
import type { ToolContext } from "../types.js";
|
||||
|
||||
export function createTaskPickupTool(api: OpenClawPluginApi) {
|
||||
return (ctx: OpenClawPluginToolContext) => ({
|
||||
return (ctx: ToolContext) => ({
|
||||
name: "task_pickup",
|
||||
label: "Task Pickup",
|
||||
description: `Pick up a task from the issue queue for a DEV or QA worker. Handles everything end-to-end: label transition, tier assignment, session creation/reuse, task dispatch, state update, and audit logging. The orchestrator should analyze the issue and pass the appropriate developer tier. Returns an announcement for the agent to post — no further session actions needed.`,
|
||||
parameters: {
|
||||
type: "object",
|
||||
required: ["issueId", "role", "projectGroupId"],
|
||||
properties: {
|
||||
issueId: { type: "number", description: "Issue ID to pick up" },
|
||||
role: { type: "string", enum: ["dev", "qa"], description: "Worker role: dev or qa" },
|
||||
role: {
|
||||
type: "string",
|
||||
enum: ["dev", "qa"],
|
||||
description: "Worker role: dev or qa",
|
||||
},
|
||||
projectGroupId: {
|
||||
type: "string",
|
||||
description: "Telegram group ID (key in projects.json). Required — pass the group ID from the current conversation.",
|
||||
description:
|
||||
"Telegram group ID (key in projects.json). Required — pass the group ID from the current conversation.",
|
||||
},
|
||||
model: {
|
||||
type: "string",
|
||||
description: "Developer tier (junior, medior, senior, qa). The orchestrator should evaluate the task complexity and choose the right tier. Falls back to keyword heuristic if omitted.",
|
||||
description:
|
||||
"Developer tier (junior, medior, senior, qa). The orchestrator should evaluate the task complexity and choose the right tier. Falls back to keyword heuristic if omitted.",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -72,7 +81,9 @@ export function createTaskPickupTool(api: OpenClawPluginApi) {
|
||||
// 3. Fetch issue and verify state
|
||||
const repoPath = resolveRepoPath(project.repo);
|
||||
const glabOpts = {
|
||||
glabPath: (api.pluginConfig as Record<string, unknown>)?.glabPath as string | undefined,
|
||||
glabPath: (api.pluginConfig as Record<string, unknown>)?.glabPath as
|
||||
| string
|
||||
| undefined,
|
||||
repoPath,
|
||||
};
|
||||
|
||||
@@ -100,14 +111,20 @@ export function createTaskPickupTool(api: OpenClawPluginApi) {
|
||||
modelReason = "LLM-selected by orchestrator";
|
||||
modelSource = "llm";
|
||||
} else {
|
||||
const selected = selectModel(issue.title, issue.description ?? "", role);
|
||||
const selected = selectModel(
|
||||
issue.title,
|
||||
issue.description ?? "",
|
||||
role,
|
||||
);
|
||||
modelAlias = selected.tier;
|
||||
modelReason = selected.reason;
|
||||
modelSource = "heuristic";
|
||||
}
|
||||
|
||||
// 5. Dispatch via shared logic
|
||||
const pluginConfig = api.pluginConfig as Record<string, unknown> | undefined;
|
||||
const pluginConfig = api.pluginConfig as
|
||||
| Record<string, unknown>
|
||||
| undefined;
|
||||
const dispatchResult = await dispatchTask({
|
||||
workspaceDir,
|
||||
agentId: ctx.agentId,
|
||||
@@ -147,9 +164,7 @@ export function createTaskPickupTool(api: OpenClawPluginApi) {
|
||||
result.tokensSavedEstimate = "~50K (session reuse)";
|
||||
}
|
||||
|
||||
return {
|
||||
content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
|
||||
};
|
||||
return jsonResult(result);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user