toolcraft 0.0.1 → 0.0.3
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 +458 -58
- package/dist/cli.compile-check.js +2 -1
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +771 -43
- package/dist/human-in-loop/approval-tasks.d.ts +31 -0
- package/dist/human-in-loop/approval-tasks.js +201 -0
- package/dist/human-in-loop/approvals-commands.d.ts +11 -0
- package/dist/human-in-loop/approvals-commands.js +191 -0
- package/dist/human-in-loop/config.d.ts +11 -0
- package/dist/human-in-loop/config.js +21 -0
- package/dist/human-in-loop/default-provider.d.ts +2 -0
- package/dist/human-in-loop/default-provider.js +26 -0
- package/dist/human-in-loop/gate.d.ts +4 -0
- package/dist/human-in-loop/gate.js +57 -0
- package/dist/human-in-loop/index.d.ts +7 -0
- package/dist/human-in-loop/index.js +4 -0
- package/dist/human-in-loop/runner.d.ts +3 -0
- package/dist/human-in-loop/runner.js +196 -0
- package/dist/human-in-loop/spawn.d.ts +3 -0
- package/dist/human-in-loop/spawn.js +16 -0
- package/dist/human-in-loop/state-machine.d.ts +4 -0
- package/dist/human-in-loop/state-machine.js +10 -0
- package/dist/human-in-loop/types.d.ts +41 -0
- package/dist/human-in-loop/types.js +13 -0
- package/dist/index.compile-check.js +25 -1
- package/dist/index.d.ts +35 -16
- package/dist/index.js +89 -24
- package/dist/json-schema-converter.d.ts +21 -0
- package/dist/json-schema-converter.js +432 -0
- package/dist/mcp-proxy.d.ts +8 -0
- package/dist/mcp-proxy.js +383 -0
- package/dist/mcp.compile-check.js +3 -2
- package/dist/mcp.d.ts +2 -0
- package/dist/mcp.js +104 -12
- package/dist/number-schema.d.ts +1 -1
- package/dist/schema-scope.d.ts +1 -1
- package/dist/sdk.compile-check.js +78 -1
- package/dist/sdk.d.ts +15 -6
- package/dist/sdk.js +57 -6
- package/dist/user-error.d.ts +3 -0
- package/dist/user-error.js +6 -0
- package/node_modules/@poe-code/agent-human-in-loop/README.md +42 -0
- package/node_modules/@poe-code/agent-human-in-loop/dist/index.d.ts +5 -0
- package/node_modules/@poe-code/agent-human-in-loop/dist/index.js +3 -0
- package/node_modules/@poe-code/agent-human-in-loop/dist/providers/mock.d.ts +2 -0
- package/node_modules/@poe-code/agent-human-in-loop/dist/providers/mock.js +11 -0
- package/node_modules/@poe-code/agent-human-in-loop/dist/providers/osascript-script.d.ts +4 -0
- package/node_modules/@poe-code/agent-human-in-loop/dist/providers/osascript-script.js +40 -0
- package/node_modules/@poe-code/agent-human-in-loop/dist/providers/osascript.d.ts +6 -0
- package/node_modules/@poe-code/agent-human-in-loop/dist/providers/osascript.js +33 -0
- package/node_modules/@poe-code/agent-human-in-loop/dist/request-approval.d.ts +4 -0
- package/node_modules/@poe-code/agent-human-in-loop/dist/request-approval.js +4 -0
- package/node_modules/@poe-code/agent-human-in-loop/dist/types.d.ts +14 -0
- package/node_modules/@poe-code/agent-human-in-loop/dist/types.js +1 -0
- package/node_modules/@poe-code/agent-human-in-loop/package.json +25 -0
- package/node_modules/@poe-code/agent-mcp-config/dist/apply.d.ts +6 -0
- package/node_modules/@poe-code/agent-mcp-config/dist/apply.js +175 -0
- package/node_modules/@poe-code/agent-mcp-config/dist/configs.d.ts +22 -0
- package/node_modules/@poe-code/agent-mcp-config/dist/configs.js +74 -0
- package/node_modules/@poe-code/agent-mcp-config/dist/index.d.ts +3 -0
- package/node_modules/@poe-code/agent-mcp-config/dist/index.js +2 -0
- package/node_modules/@poe-code/agent-mcp-config/dist/shapes.d.ts +31 -0
- package/node_modules/@poe-code/agent-mcp-config/dist/shapes.js +87 -0
- package/node_modules/@poe-code/agent-mcp-config/dist/types.d.ts +25 -0
- package/node_modules/@poe-code/agent-mcp-config/dist/types.js +1 -0
- package/node_modules/@poe-code/agent-mcp-config/package.json +25 -0
- package/node_modules/@poe-code/design-system/dist/prompts/primitives/cancel.d.ts +1 -1
- package/node_modules/@poe-code/design-system/dist/prompts/primitives/cancel.js +1 -1
- package/node_modules/@poe-code/task-list/README.md +114 -0
- package/node_modules/@poe-code/task-list/dist/backends/markdown-dir.d.ts +2 -0
- package/node_modules/@poe-code/task-list/dist/backends/markdown-dir.js +466 -0
- package/node_modules/@poe-code/task-list/dist/backends/utils.d.ts +8 -0
- package/node_modules/@poe-code/task-list/dist/backends/utils.js +58 -0
- package/node_modules/@poe-code/task-list/dist/backends/yaml-file.d.ts +2 -0
- package/node_modules/@poe-code/task-list/dist/backends/yaml-file.js +444 -0
- package/node_modules/@poe-code/task-list/dist/index.d.ts +4 -0
- package/node_modules/@poe-code/task-list/dist/index.js +4 -0
- package/node_modules/@poe-code/task-list/dist/open.d.ts +3 -0
- package/node_modules/@poe-code/task-list/dist/open.js +34 -0
- package/node_modules/@poe-code/task-list/dist/schema/store.schema.json +32 -0
- package/node_modules/@poe-code/task-list/dist/schema/task.schema.json +33 -0
- package/node_modules/@poe-code/task-list/dist/state-machine.d.ts +16 -0
- package/node_modules/@poe-code/task-list/dist/state-machine.js +67 -0
- package/node_modules/@poe-code/task-list/dist/state.d.ts +29 -0
- package/node_modules/@poe-code/task-list/dist/state.js +61 -0
- package/node_modules/@poe-code/task-list/dist/types.d.ts +116 -0
- package/node_modules/@poe-code/task-list/dist/types.js +37 -0
- package/node_modules/@poe-code/task-list/package.json +26 -0
- package/package.json +25 -10
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
3
|
+
import { runMutations, configMutation, fileMutation, readFileIfExists } from "@poe-code/config-mutations";
|
|
4
|
+
import { getAgentConfig, resolveConfigPath, isSupported } from "./configs.js";
|
|
5
|
+
import { getShapeTransformer } from "./shapes.js";
|
|
6
|
+
function getConfigDirectory(configPath) {
|
|
7
|
+
return path.dirname(configPath);
|
|
8
|
+
}
|
|
9
|
+
export class UnsupportedAgentError extends Error {
|
|
10
|
+
constructor(agentId) {
|
|
11
|
+
super(`Unsupported agent: ${agentId}`);
|
|
12
|
+
this.name = "UnsupportedAgentError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function isConfigObject(value) {
|
|
16
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
17
|
+
}
|
|
18
|
+
function resolveServerMap(document, configKey) {
|
|
19
|
+
const value = document[configKey];
|
|
20
|
+
return isConfigObject(value) ? value : {};
|
|
21
|
+
}
|
|
22
|
+
function mergeServerMap(document, configKey, servers) {
|
|
23
|
+
return { ...document, [configKey]: servers };
|
|
24
|
+
}
|
|
25
|
+
function expandHomePath(configPath, homeDir) {
|
|
26
|
+
if (!configPath.startsWith("~")) {
|
|
27
|
+
return configPath;
|
|
28
|
+
}
|
|
29
|
+
if (configPath === "~") {
|
|
30
|
+
return homeDir;
|
|
31
|
+
}
|
|
32
|
+
if (configPath.startsWith("~/")) {
|
|
33
|
+
return path.join(homeDir, configPath.slice(2));
|
|
34
|
+
}
|
|
35
|
+
return path.join(homeDir, configPath.slice(1));
|
|
36
|
+
}
|
|
37
|
+
function parseYamlDocument(content) {
|
|
38
|
+
if (content.trim() === "") {
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
41
|
+
const parsed = parseYaml(content);
|
|
42
|
+
if (parsed === null || parsed === undefined) {
|
|
43
|
+
return {};
|
|
44
|
+
}
|
|
45
|
+
if (!isConfigObject(parsed)) {
|
|
46
|
+
throw new Error("Expected YAML document to be an object.");
|
|
47
|
+
}
|
|
48
|
+
return parsed;
|
|
49
|
+
}
|
|
50
|
+
function serializeYamlDocument(document) {
|
|
51
|
+
const serialized = stringifyYaml(document);
|
|
52
|
+
return serialized.endsWith("\n") ? serialized : `${serialized}\n`;
|
|
53
|
+
}
|
|
54
|
+
async function readYamlConfig(configPath, options) {
|
|
55
|
+
const absolutePath = expandHomePath(configPath, options.homeDir);
|
|
56
|
+
const existingContent = await readFileIfExists(options.fs, absolutePath);
|
|
57
|
+
if (existingContent === null) {
|
|
58
|
+
return {};
|
|
59
|
+
}
|
|
60
|
+
return parseYamlDocument(existingContent);
|
|
61
|
+
}
|
|
62
|
+
async function writeYamlConfig(configPath, document, options) {
|
|
63
|
+
if (options.dryRun) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const absolutePath = expandHomePath(configPath, options.homeDir);
|
|
67
|
+
const configDir = path.dirname(absolutePath);
|
|
68
|
+
await options.fs.mkdir(configDir, { recursive: true });
|
|
69
|
+
await options.fs.writeFile(absolutePath, serializeYamlDocument(document), {
|
|
70
|
+
encoding: "utf8"
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function removeServer(document, configKey, serverName) {
|
|
74
|
+
const servers = resolveServerMap(document, configKey);
|
|
75
|
+
if (!(serverName in servers)) {
|
|
76
|
+
return { changed: false, content: document };
|
|
77
|
+
}
|
|
78
|
+
const nextServers = { ...servers };
|
|
79
|
+
delete nextServers[serverName];
|
|
80
|
+
if (Object.keys(nextServers).length === 0) {
|
|
81
|
+
const nextDocument = { ...document };
|
|
82
|
+
delete nextDocument[configKey];
|
|
83
|
+
return { changed: true, content: nextDocument };
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
changed: true,
|
|
87
|
+
content: mergeServerMap(document, configKey, nextServers)
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
export async function configure(agentId, server, options) {
|
|
91
|
+
if (!isSupported(agentId)) {
|
|
92
|
+
throw new UnsupportedAgentError(agentId);
|
|
93
|
+
}
|
|
94
|
+
const config = getAgentConfig(agentId);
|
|
95
|
+
const configPath = resolveConfigPath(config, options.platform);
|
|
96
|
+
const shapeTransformer = getShapeTransformer(config.shape);
|
|
97
|
+
const shaped = shapeTransformer(server);
|
|
98
|
+
if (shaped === undefined) {
|
|
99
|
+
await unconfigure(agentId, server.name, options);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (config.format === "yaml") {
|
|
103
|
+
const document = await readYamlConfig(configPath, options);
|
|
104
|
+
const servers = resolveServerMap(document, config.configKey);
|
|
105
|
+
const nextDocument = mergeServerMap(document, config.configKey, {
|
|
106
|
+
...servers,
|
|
107
|
+
[server.name]: shaped
|
|
108
|
+
});
|
|
109
|
+
await writeYamlConfig(configPath, nextDocument, options);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const configDir = getConfigDirectory(configPath);
|
|
113
|
+
await runMutations([
|
|
114
|
+
fileMutation.ensureDirectory({
|
|
115
|
+
path: configDir,
|
|
116
|
+
label: `Ensure directory ${configDir}`
|
|
117
|
+
}),
|
|
118
|
+
// Use transform to replace the server entry entirely (not deep-merge)
|
|
119
|
+
// This ensures old fields like 'args' are removed when switching to array 'command'
|
|
120
|
+
configMutation.transform({
|
|
121
|
+
target: configPath,
|
|
122
|
+
format: config.format,
|
|
123
|
+
transform: (document) => {
|
|
124
|
+
const servers = resolveServerMap(document, config.configKey);
|
|
125
|
+
const newServers = {
|
|
126
|
+
...servers,
|
|
127
|
+
[server.name]: shaped
|
|
128
|
+
};
|
|
129
|
+
return {
|
|
130
|
+
changed: true,
|
|
131
|
+
content: mergeServerMap(document, config.configKey, newServers)
|
|
132
|
+
};
|
|
133
|
+
},
|
|
134
|
+
label: `Add ${server.name} to ${configPath}`
|
|
135
|
+
})
|
|
136
|
+
], {
|
|
137
|
+
fs: options.fs,
|
|
138
|
+
homeDir: options.homeDir,
|
|
139
|
+
dryRun: options.dryRun,
|
|
140
|
+
observers: options.observers
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
export async function unconfigure(agentId, serverName, options) {
|
|
144
|
+
if (!isSupported(agentId)) {
|
|
145
|
+
throw new UnsupportedAgentError(agentId);
|
|
146
|
+
}
|
|
147
|
+
const config = getAgentConfig(agentId);
|
|
148
|
+
const configPath = resolveConfigPath(config, options.platform);
|
|
149
|
+
if (config.format === "yaml") {
|
|
150
|
+
const document = await readYamlConfig(configPath, options);
|
|
151
|
+
const { changed, content } = removeServer(document, config.configKey, serverName);
|
|
152
|
+
if (!changed) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
await writeYamlConfig(configPath, content, options);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
await runMutations([
|
|
159
|
+
configMutation.prune({
|
|
160
|
+
target: configPath,
|
|
161
|
+
format: config.format,
|
|
162
|
+
shape: {
|
|
163
|
+
[config.configKey]: {
|
|
164
|
+
[serverName]: {}
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
label: `Remove ${serverName} from ${configPath}`
|
|
168
|
+
})
|
|
169
|
+
], {
|
|
170
|
+
fs: options.fs,
|
|
171
|
+
homeDir: options.homeDir,
|
|
172
|
+
dryRun: options.dryRun,
|
|
173
|
+
observers: options.observers
|
|
174
|
+
});
|
|
175
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ShapeName } from "./shapes.js";
|
|
2
|
+
export type ConfigFormat = "json" | "toml" | "yaml";
|
|
3
|
+
export type Platform = "darwin" | "linux" | "win32";
|
|
4
|
+
export interface AgentMcpConfig {
|
|
5
|
+
configFile: string | ((platform: Platform) => string);
|
|
6
|
+
configKey: string;
|
|
7
|
+
format: ConfigFormat;
|
|
8
|
+
shape: ShapeName;
|
|
9
|
+
mcpOutputFormat?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare const supportedAgents: readonly string[];
|
|
12
|
+
export type AgentSupportStatus = "supported" | "unsupported" | "unknown";
|
|
13
|
+
export interface AgentSupportResult {
|
|
14
|
+
status: AgentSupportStatus;
|
|
15
|
+
input: string;
|
|
16
|
+
id?: string;
|
|
17
|
+
config?: AgentMcpConfig;
|
|
18
|
+
}
|
|
19
|
+
export declare function resolveAgentSupport(input: string, registry?: Record<string, AgentMcpConfig>): AgentSupportResult;
|
|
20
|
+
export declare function isSupported(agentId: string): boolean;
|
|
21
|
+
export declare function getAgentConfig(agentId: string): AgentMcpConfig | undefined;
|
|
22
|
+
export declare function resolveConfigPath(config: AgentMcpConfig, platform: Platform): string;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { resolveAgentId } from "@poe-code/agent-defs";
|
|
2
|
+
const agentMcpConfigs = {
|
|
3
|
+
"claude-code": {
|
|
4
|
+
configFile: "~/.claude.json",
|
|
5
|
+
configKey: "mcpServers",
|
|
6
|
+
format: "json",
|
|
7
|
+
shape: "standard"
|
|
8
|
+
},
|
|
9
|
+
"claude-desktop": {
|
|
10
|
+
configFile: (platform) => {
|
|
11
|
+
switch (platform) {
|
|
12
|
+
case "darwin":
|
|
13
|
+
return "~/Library/Application Support/Claude/claude_desktop_config.json";
|
|
14
|
+
case "win32":
|
|
15
|
+
return "~/AppData/Roaming/Claude/claude_desktop_config.json";
|
|
16
|
+
default:
|
|
17
|
+
return "~/.config/Claude/claude_desktop_config.json";
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
configKey: "mcpServers",
|
|
21
|
+
format: "json",
|
|
22
|
+
shape: "standard",
|
|
23
|
+
mcpOutputFormat: "markdown_instructions"
|
|
24
|
+
},
|
|
25
|
+
codex: {
|
|
26
|
+
configFile: "~/.codex/config.toml",
|
|
27
|
+
configKey: "mcp_servers",
|
|
28
|
+
format: "toml",
|
|
29
|
+
shape: "standard"
|
|
30
|
+
},
|
|
31
|
+
opencode: {
|
|
32
|
+
configFile: "~/.config/opencode/opencode.json",
|
|
33
|
+
configKey: "mcp",
|
|
34
|
+
format: "json",
|
|
35
|
+
shape: "opencode"
|
|
36
|
+
},
|
|
37
|
+
kimi: {
|
|
38
|
+
configFile: "~/.kimi/mcp.json",
|
|
39
|
+
configKey: "mcpServers",
|
|
40
|
+
format: "json",
|
|
41
|
+
shape: "standard"
|
|
42
|
+
},
|
|
43
|
+
goose: {
|
|
44
|
+
configFile: "~/.config/goose/config.yaml",
|
|
45
|
+
configKey: "extensions",
|
|
46
|
+
format: "yaml",
|
|
47
|
+
shape: "goose"
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
export const supportedAgents = Object.keys(agentMcpConfigs);
|
|
51
|
+
export function resolveAgentSupport(input, registry = agentMcpConfigs) {
|
|
52
|
+
const resolvedId = resolveAgentId(input);
|
|
53
|
+
if (!resolvedId) {
|
|
54
|
+
return { status: "unknown", input };
|
|
55
|
+
}
|
|
56
|
+
const config = registry[resolvedId];
|
|
57
|
+
if (!config) {
|
|
58
|
+
return { status: "unsupported", input, id: resolvedId };
|
|
59
|
+
}
|
|
60
|
+
return { status: "supported", input, id: resolvedId, config };
|
|
61
|
+
}
|
|
62
|
+
export function isSupported(agentId) {
|
|
63
|
+
return resolveAgentSupport(agentId).status === "supported";
|
|
64
|
+
}
|
|
65
|
+
export function getAgentConfig(agentId) {
|
|
66
|
+
const support = resolveAgentSupport(agentId);
|
|
67
|
+
return support.status === "supported" ? support.config : undefined;
|
|
68
|
+
}
|
|
69
|
+
export function resolveConfigPath(config, platform) {
|
|
70
|
+
if (typeof config.configFile === "function") {
|
|
71
|
+
return config.configFile(platform);
|
|
72
|
+
}
|
|
73
|
+
return config.configFile;
|
|
74
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { McpServerEntry } from "./types.js";
|
|
2
|
+
export type ShapeName = "standard" | "opencode" | "goose";
|
|
3
|
+
export interface StandardShapeOutput {
|
|
4
|
+
command: string;
|
|
5
|
+
args?: string[];
|
|
6
|
+
env?: Record<string, string>;
|
|
7
|
+
}
|
|
8
|
+
export interface OpencodeShapeOutput {
|
|
9
|
+
type: "local";
|
|
10
|
+
command: string[];
|
|
11
|
+
env?: Record<string, string>;
|
|
12
|
+
enabled: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface GooseStdioShapeOutput {
|
|
15
|
+
type: "stdio";
|
|
16
|
+
cmd: string;
|
|
17
|
+
args?: string[];
|
|
18
|
+
envs?: Record<string, string>;
|
|
19
|
+
}
|
|
20
|
+
export interface GooseHttpShapeOutput {
|
|
21
|
+
type: "http";
|
|
22
|
+
url: string;
|
|
23
|
+
headers?: Record<string, string>;
|
|
24
|
+
}
|
|
25
|
+
export type GooseShapeOutput = GooseStdioShapeOutput | GooseHttpShapeOutput;
|
|
26
|
+
export type ShapeOutput = StandardShapeOutput | OpencodeShapeOutput | GooseShapeOutput;
|
|
27
|
+
export type ShapeTransformer = (entry: McpServerEntry) => ShapeOutput | undefined;
|
|
28
|
+
export declare function standardShape(entry: McpServerEntry): ShapeOutput | undefined;
|
|
29
|
+
export declare function opencodeShape(entry: McpServerEntry): OpencodeShapeOutput;
|
|
30
|
+
export declare function gooseShape(entry: McpServerEntry): GooseShapeOutput | undefined;
|
|
31
|
+
export declare function getShapeTransformer(shape: ShapeName): ShapeTransformer;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
function transformStdioServer(config, enabled) {
|
|
2
|
+
if (!enabled) {
|
|
3
|
+
return undefined;
|
|
4
|
+
}
|
|
5
|
+
const result = {
|
|
6
|
+
command: config.command
|
|
7
|
+
};
|
|
8
|
+
if (config.args && config.args.length > 0) {
|
|
9
|
+
result.args = config.args;
|
|
10
|
+
}
|
|
11
|
+
if (config.env && Object.keys(config.env).length > 0) {
|
|
12
|
+
result.env = config.env;
|
|
13
|
+
}
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
export function standardShape(entry) {
|
|
17
|
+
const enabled = entry.enabled !== false;
|
|
18
|
+
if (entry.config.transport === "stdio") {
|
|
19
|
+
return transformStdioServer(entry.config, enabled);
|
|
20
|
+
}
|
|
21
|
+
if (!enabled) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
command: entry.config.url
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function transformStdioServerOpencode(config, enabled) {
|
|
29
|
+
const command = config.args && config.args.length > 0
|
|
30
|
+
? [config.command, ...config.args]
|
|
31
|
+
: [config.command];
|
|
32
|
+
const result = {
|
|
33
|
+
type: "local",
|
|
34
|
+
command,
|
|
35
|
+
enabled
|
|
36
|
+
};
|
|
37
|
+
if (config.env && Object.keys(config.env).length > 0) {
|
|
38
|
+
result.env = config.env;
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
export function opencodeShape(entry) {
|
|
43
|
+
const enabled = entry.enabled !== false;
|
|
44
|
+
if (entry.config.transport === "stdio") {
|
|
45
|
+
return transformStdioServerOpencode(entry.config, enabled);
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
type: "local",
|
|
49
|
+
command: [entry.config.url],
|
|
50
|
+
enabled
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export function gooseShape(entry) {
|
|
54
|
+
const enabled = entry.enabled !== false;
|
|
55
|
+
if (!enabled) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
if (entry.config.transport === "stdio") {
|
|
59
|
+
const result = {
|
|
60
|
+
type: "stdio",
|
|
61
|
+
cmd: entry.config.command
|
|
62
|
+
};
|
|
63
|
+
if (entry.config.args && entry.config.args.length > 0) {
|
|
64
|
+
result.args = entry.config.args;
|
|
65
|
+
}
|
|
66
|
+
if (entry.config.env && Object.keys(entry.config.env).length > 0) {
|
|
67
|
+
result.envs = entry.config.env;
|
|
68
|
+
}
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
const result = {
|
|
72
|
+
type: "http",
|
|
73
|
+
url: entry.config.url
|
|
74
|
+
};
|
|
75
|
+
if (entry.config.headers && Object.keys(entry.config.headers).length > 0) {
|
|
76
|
+
result.headers = entry.config.headers;
|
|
77
|
+
}
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
const shapeTransformers = {
|
|
81
|
+
standard: standardShape,
|
|
82
|
+
opencode: opencodeShape,
|
|
83
|
+
goose: gooseShape
|
|
84
|
+
};
|
|
85
|
+
export function getShapeTransformer(shape) {
|
|
86
|
+
return shapeTransformers[shape];
|
|
87
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { FileSystem, MutationObservers } from "@poe-code/config-mutations";
|
|
2
|
+
export interface McpStdioServer {
|
|
3
|
+
transport: "stdio";
|
|
4
|
+
command: string;
|
|
5
|
+
args?: string[];
|
|
6
|
+
env?: Record<string, string>;
|
|
7
|
+
}
|
|
8
|
+
export interface McpHttpServer {
|
|
9
|
+
transport: "http";
|
|
10
|
+
url: string;
|
|
11
|
+
headers?: Record<string, string>;
|
|
12
|
+
}
|
|
13
|
+
export type McpServerConfig = McpStdioServer | McpHttpServer;
|
|
14
|
+
export interface McpServerEntry {
|
|
15
|
+
name: string;
|
|
16
|
+
config: McpServerConfig;
|
|
17
|
+
enabled?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface ApplyOptions {
|
|
20
|
+
fs: FileSystem;
|
|
21
|
+
homeDir: string;
|
|
22
|
+
platform: "darwin" | "linux" | "win32";
|
|
23
|
+
dryRun?: boolean;
|
|
24
|
+
observers?: MutationObservers;
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@poe-code/agent-mcp-config",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@poe-code/agent-defs": "*",
|
|
22
|
+
"@poe-code/config-mutations": "*",
|
|
23
|
+
"yaml": "^2.8.3"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { isCancel } from "@clack/
|
|
1
|
+
export { isCancel } from "@clack/prompts";
|
|
2
2
|
export declare function cancel(msg?: string): void;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# @poe-code/task-list
|
|
2
|
+
|
|
3
|
+
Multi-list task manager with pluggable storage backends.
|
|
4
|
+
|
|
5
|
+
## Backends
|
|
6
|
+
|
|
7
|
+
`@poe-code/task-list` exposes one API over two backends:
|
|
8
|
+
|
|
9
|
+
- `markdown-dir`: one Markdown file per task, organized into subdirectories per list
|
|
10
|
+
- `yaml-file`: one YAML document with a top-level `lists:` mapping
|
|
11
|
+
|
|
12
|
+
The task lifecycle is `draft -> planned -> in-progress -> done -> archived`. `archived` is terminal.
|
|
13
|
+
|
|
14
|
+
## Public API
|
|
15
|
+
|
|
16
|
+
- `openTaskList(options)`: opens a task store and returns a `TaskList`
|
|
17
|
+
- `TaskList`: top-level interface for listing lists, querying all tasks, and resolving qualified IDs
|
|
18
|
+
- `Tasks`: per-list interface for create, update, `fire`, `canFire`, `events`, delete, and list operations
|
|
19
|
+
- `Task`: normalized task record with `list`, `id`, `qualifiedId`, `name`, `state`, `description`, and `metadata`
|
|
20
|
+
- `TaskState`: `"draft" | "planned" | "in-progress" | "done" | "archived"`
|
|
21
|
+
- `TaskDefaults`: default `metadata` applied when creating new tasks
|
|
22
|
+
- `StateMachineDef` / `EventDef`: exported types for custom task lifecycle definitions passed via `openTaskList({ stateMachine })`
|
|
23
|
+
- `defaultStateMachine`: exported default lifecycle with `plan`, `start`, `complete`, and `archive` events
|
|
24
|
+
- Error classes: `TaskNotFoundError`, `TaskAlreadyExistsError`, `InvalidTransitionError`, `MalformedTaskError`
|
|
25
|
+
|
|
26
|
+
## State Machines
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
interface StateMachineDef<TState extends string = string, TEvent extends string = string> {
|
|
30
|
+
initial: TState;
|
|
31
|
+
states: readonly TState[];
|
|
32
|
+
events: Readonly<Record<TEvent, EventDef<TState>>>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface EventDef<TState extends string = string> {
|
|
36
|
+
from: readonly TState[] | "*";
|
|
37
|
+
to: TState;
|
|
38
|
+
guard?: (task: Task) => true | string;
|
|
39
|
+
onEnter?: (task: Task) => void | Promise<void>;
|
|
40
|
+
onExit?: (task: Task) => void | Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Pass a custom machine with `openTaskList({ stateMachine })`. If omitted, the package uses `defaultStateMachine`, whose event names are `plan`, `start`, `complete`, and `archive`.
|
|
45
|
+
|
|
46
|
+
## Options
|
|
47
|
+
|
|
48
|
+
| Option | Type | Default | Behavior |
|
|
49
|
+
| --- | --- | --- | --- |
|
|
50
|
+
| `type` | `"markdown-dir" \| "yaml-file"` | required | Selects the backend implementation. |
|
|
51
|
+
| `path` | `string` | required | Root directory for `markdown-dir` or YAML file path for `yaml-file`. |
|
|
52
|
+
| `defaults` | `TaskDefaults` | `{ metadata: {} }` | Seeds omitted metadata on new tasks only. New tasks always start at the configured state machine's initial state. |
|
|
53
|
+
| `create` | `boolean` | `false` | Creates missing storage for the selected backend when enabled. |
|
|
54
|
+
| `lockStaleMs` | `number` | `30_000` | Stale threshold passed to backend file locking. |
|
|
55
|
+
| `lockRetries` | `number` | `20` | Retry count passed to backend file locking. |
|
|
56
|
+
| `fs` | `TaskListFs` | `node:fs/promises` adapter | Injectable filesystem, primarily for tests. |
|
|
57
|
+
| `stateMachine` | `StateMachineDef` | `defaultStateMachine` | Overrides the task lifecycle used by `create`, `fire`, `canFire`, and `events`. |
|
|
58
|
+
|
|
59
|
+
## Env vars
|
|
60
|
+
|
|
61
|
+
None.
|
|
62
|
+
|
|
63
|
+
## Usage
|
|
64
|
+
|
|
65
|
+
### `markdown-dir`
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { openTaskList } from "@poe-code/task-list";
|
|
69
|
+
|
|
70
|
+
const taskList = await openTaskList({
|
|
71
|
+
type: "markdown-dir",
|
|
72
|
+
path: "/repo/tasks",
|
|
73
|
+
create: true
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const planning = taskList.list("planning");
|
|
77
|
+
|
|
78
|
+
await planning.create({
|
|
79
|
+
id: "ship-readme",
|
|
80
|
+
name: "Ship package README"
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
await planning.fire("ship-readme", "plan");
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### `yaml-file`
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { openTaskList } from "@poe-code/task-list";
|
|
90
|
+
|
|
91
|
+
const taskList = await openTaskList({
|
|
92
|
+
type: "yaml-file",
|
|
93
|
+
path: "/repo/tasks.yaml",
|
|
94
|
+
create: true
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const planning = taskList.list("planning");
|
|
98
|
+
|
|
99
|
+
await planning.create({
|
|
100
|
+
id: "review-release",
|
|
101
|
+
name: "Review release checklist"
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
await planning.fire("review-release", "plan");
|
|
105
|
+
await planning.fire("review-release", "start");
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Notes
|
|
109
|
+
|
|
110
|
+
The package never overwrites existing task files or store files. `defaults.metadata` is applied only when creating new tasks and does not retroactively update existing tasks.
|
|
111
|
+
|
|
112
|
+
Task state changes are event-driven: use `fire(id, event)` to move between states, `canFire(id, event)` to check whether an event is currently legal, and `events(id)` to list the currently legal event names. There is no `transition()` API.
|
|
113
|
+
|
|
114
|
+
`create()` always starts new tasks at `stateMachine.initial`. `update()` cannot change `state`; use `fire()` instead.
|