@openspoon/subtask2 0.1.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 +56 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +98 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# @openspoon/subtask2
|
|
2
|
+
|
|
3
|
+
OpenCode plugin for enhanced subtask control with **return context injection** and **prompt chaining**.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **`return`**: Append context to subtask output, ensuring the parent agent receives specific information
|
|
8
|
+
- **`chain`**: Queue follow-up user messages that execute sequentially after the subtask completes
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
Add to your `opencode.json`:
|
|
13
|
+
|
|
14
|
+
```json
|
|
15
|
+
{
|
|
16
|
+
"plugins": ["@openspoon/subtask2"]
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
or
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install @openspoon/subtask2
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
Add `return` and/or `chain` to your command frontmatter:
|
|
29
|
+
|
|
30
|
+
### Example: Code Review Command
|
|
31
|
+
|
|
32
|
+
`.opencode/command/review.md`
|
|
33
|
+
|
|
34
|
+
```markdown
|
|
35
|
+
---
|
|
36
|
+
description: Review code changes and create summary
|
|
37
|
+
agent: general
|
|
38
|
+
subtask: true
|
|
39
|
+
return: You are the agent in charge of assessing the bug review, challenge, verify and validate it, then discard it or implement it.
|
|
40
|
+
chain:
|
|
41
|
+
- Let's now rinse and repeat with PR#356, use the task tool to review it for bugs etc... then assess, challenge, validate -> discard or implement.
|
|
42
|
+
- Rinse and repeat, with next PR.
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
Review PR#355 for bugs, security issues, and code style problems.
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## How It Works
|
|
49
|
+
|
|
50
|
+
1. When a subtask command with `return` executes, the return text is appended to the task output
|
|
51
|
+
2. When the subtask completes, each `chain` prompt is sent as a synthetic user message
|
|
52
|
+
3. Chain prompts execute sequentially, each waiting for the previous to complete
|
|
53
|
+
|
|
54
|
+
## License
|
|
55
|
+
|
|
56
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAiElD,QAAA,MAAM,MAAM,EAAE,MAqCb,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
function parseFrontmatter(content) {
|
|
2
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
3
|
+
if (!match)
|
|
4
|
+
return {};
|
|
5
|
+
const fm = {};
|
|
6
|
+
const lines = match[1].split("\n");
|
|
7
|
+
for (let i = 0; i < lines.length; i++) {
|
|
8
|
+
const line = lines[i];
|
|
9
|
+
const keyMatch = line.match(/^(\w+):\s*(.*)/);
|
|
10
|
+
if (!keyMatch)
|
|
11
|
+
continue;
|
|
12
|
+
const [, key, value] = keyMatch;
|
|
13
|
+
if (!value.trim()) {
|
|
14
|
+
const items = [];
|
|
15
|
+
while (i + 1 < lines.length && lines[i + 1].match(/^\s+-\s+/)) {
|
|
16
|
+
i++;
|
|
17
|
+
items.push(lines[i].replace(/^\s+-\s+/, "").trim());
|
|
18
|
+
}
|
|
19
|
+
if (items.length) {
|
|
20
|
+
fm[key] = items;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
fm[key] = value.trim();
|
|
25
|
+
}
|
|
26
|
+
return fm;
|
|
27
|
+
}
|
|
28
|
+
async function buildManifest() {
|
|
29
|
+
const manifest = {};
|
|
30
|
+
const home = Bun.env.HOME ?? "";
|
|
31
|
+
const dirs = [`${home}/.config/opencode/command`, `${Bun.env.PWD ?? "."}/.opencode/command`];
|
|
32
|
+
for (const dir of dirs) {
|
|
33
|
+
try {
|
|
34
|
+
const glob = new Bun.Glob("*.md");
|
|
35
|
+
for await (const file of glob.scan(dir)) {
|
|
36
|
+
const name = file.replace(/\.md$/, "");
|
|
37
|
+
const content = await Bun.file(`${dir}/${file}`).text();
|
|
38
|
+
const fm = parseFrontmatter(content);
|
|
39
|
+
const chain = fm.chain;
|
|
40
|
+
const chainArr = chain ? (Array.isArray(chain) ? chain : [chain]) : [];
|
|
41
|
+
if (fm.return || chainArr.length) {
|
|
42
|
+
manifest[name] = {
|
|
43
|
+
return: fm.return,
|
|
44
|
+
chain: chainArr,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch { }
|
|
50
|
+
}
|
|
51
|
+
return manifest;
|
|
52
|
+
}
|
|
53
|
+
let configs = {};
|
|
54
|
+
let client = null;
|
|
55
|
+
const callState = new Map();
|
|
56
|
+
const chainState = new Map();
|
|
57
|
+
const plugin = async (ctx) => {
|
|
58
|
+
configs = await buildManifest();
|
|
59
|
+
client = ctx.client;
|
|
60
|
+
return {
|
|
61
|
+
"tool.execute.before": async (input, output) => {
|
|
62
|
+
if (input.tool !== "task")
|
|
63
|
+
return;
|
|
64
|
+
const cmd = output.args?.command;
|
|
65
|
+
if (cmd && configs[cmd]) {
|
|
66
|
+
callState.set(input.callID, cmd);
|
|
67
|
+
if (configs[cmd].chain.length) {
|
|
68
|
+
chainState.set(input.sessionID, [...configs[cmd].chain]);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"tool.execute.after": async (input, output) => {
|
|
73
|
+
if (input.tool !== "task")
|
|
74
|
+
return;
|
|
75
|
+
const cmd = callState.get(input.callID);
|
|
76
|
+
if (!cmd)
|
|
77
|
+
return;
|
|
78
|
+
if (configs[cmd]?.return) {
|
|
79
|
+
output.output += `\n\n${configs[cmd].return}`;
|
|
80
|
+
}
|
|
81
|
+
callState.delete(input.callID);
|
|
82
|
+
},
|
|
83
|
+
"experimental.text.complete": async (input) => {
|
|
84
|
+
const chain = chainState.get(input.sessionID);
|
|
85
|
+
if (!chain?.length || !client)
|
|
86
|
+
return;
|
|
87
|
+
const next = chain.shift();
|
|
88
|
+
if (!chain.length)
|
|
89
|
+
chainState.delete(input.sessionID);
|
|
90
|
+
await client.session.promptAsync({
|
|
91
|
+
path: { id: input.sessionID },
|
|
92
|
+
body: { parts: [{ type: "text", text: next, synthetic: true }] },
|
|
93
|
+
});
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
export default plugin;
|
|
98
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/package.json",
|
|
3
|
+
"name": "@openspoon/subtask2",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "Opencode plugin for enhanced subtask control with return context and prompt chaining",
|
|
7
|
+
"main": "./dist/subtask2/index.js",
|
|
8
|
+
"types": "./dist/subtask2/index.d.ts",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"clean": "rm -rf dist",
|
|
11
|
+
"build": "npm run clean && tsc",
|
|
12
|
+
"prepublishOnly": "npm run build"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"opencode",
|
|
16
|
+
"opencode-plugin",
|
|
17
|
+
"plugin",
|
|
18
|
+
"subtask",
|
|
19
|
+
"chaining",
|
|
20
|
+
"automation"
|
|
21
|
+
],
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/spoons-and-mirrors/subtask2.git"
|
|
25
|
+
},
|
|
26
|
+
"author": "openspoon",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@opencode-ai/plugin": ">=0.13.7"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@opencode-ai/sdk": "latest"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@opencode-ai/plugin": "^1.0.143",
|
|
39
|
+
"@types/node": "^24.10.1",
|
|
40
|
+
"bun-types": "^1.3.4",
|
|
41
|
+
"typescript": "^5.9.3"
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"dist/",
|
|
45
|
+
"README.md",
|
|
46
|
+
"LICENSE"
|
|
47
|
+
]
|
|
48
|
+
}
|