zenox 1.4.2 → 1.5.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 +38 -0
- package/dist/background/index.d.ts +1 -1
- package/dist/background/types.d.ts +7 -0
- package/dist/index.js +163 -18
- package/dist/orchestration/prompt.d.ts +1 -1
- package/dist/orchestration/session-agent-tracker.d.ts +33 -7
- package/dist/tools/project-guidelines/index.d.ts +1 -0
- package/dist/tools/project-guidelines/tools.d.ts +11 -0
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -25,6 +25,7 @@ Zenox supercharges [OpenCode](https://opencode.ai) with specialized AI agents th
|
|
|
25
25
|
- **Keyword Triggers** — `ultrawork`, `deep research`, `explore codebase`
|
|
26
26
|
- **Session History** — Query past sessions to learn from previous work
|
|
27
27
|
- **Code Intelligence** — Search symbols via LSP
|
|
28
|
+
- **Project Guidelines Auto-Update** — Automatically keeps AGENTS.md and CLAUDE.md up-to-date
|
|
28
29
|
- **Todo Continuation** — Auto-reminds when tasks are incomplete
|
|
29
30
|
- **Auto-Updates** — Toast notification when new version available
|
|
30
31
|
|
|
@@ -165,6 +166,43 @@ Zenox automatically reminds you to continue working when:
|
|
|
165
166
|
|
|
166
167
|
This keeps you on track without manual intervention. The agent will be prompted to continue until all todos are complete or blocked.
|
|
167
168
|
|
|
169
|
+
## Project Guidelines Auto-Update
|
|
170
|
+
|
|
171
|
+
Zenox automatically keeps your `AGENTS.md` and `CLAUDE.md` files up-to-date with important decisions, patterns, and conventions.
|
|
172
|
+
|
|
173
|
+
### The Problem
|
|
174
|
+
|
|
175
|
+
Developers forget to update documentation. Important decisions get lost. Team members repeat the same questions. Next session, the agent has no context.
|
|
176
|
+
|
|
177
|
+
### The Solution
|
|
178
|
+
|
|
179
|
+
Zenox detects important decisions and automatically documents them:
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
You: "In this project, always use Zustand for state management"
|
|
183
|
+
→ Agent checks AGENTS.md — not documented yet
|
|
184
|
+
→ Agent saves: "- State Management: Use Zustand, not Redux"
|
|
185
|
+
→ Future sessions automatically know this
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### What Gets Documented
|
|
189
|
+
|
|
190
|
+
| Trigger | Example |
|
|
191
|
+
|---------|---------|
|
|
192
|
+
| User decision | "Always use Tailwind", "We use this API pattern" |
|
|
193
|
+
| Architecture choice | Agent decides between approaches after analysis |
|
|
194
|
+
| Reusable code | Agent creates a utility worth reusing |
|
|
195
|
+
| Convention discovered | Agent notices consistent patterns in codebase |
|
|
196
|
+
|
|
197
|
+
### How It Works
|
|
198
|
+
|
|
199
|
+
1. Agent recognizes something important
|
|
200
|
+
2. Reads `AGENTS.md` / `CLAUDE.md` to check if already documented
|
|
201
|
+
3. If not there → calls `save_project_guideline` to add it
|
|
202
|
+
4. Both files get updated (or `AGENTS.md` created if neither exists)
|
|
203
|
+
|
|
204
|
+
**Zero manual work** — your project documentation stays current automatically.
|
|
205
|
+
|
|
168
206
|
## Configuration
|
|
169
207
|
|
|
170
208
|
### Custom Models
|
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { BackgroundManager } from "./manager";
|
|
7
7
|
export { createBackgroundTools, type BackgroundTools } from "./tools";
|
|
8
|
-
export type { BackgroundTask, TaskStatus, LaunchInput, CompletionNotification, } from "./types";
|
|
8
|
+
export type { BackgroundTask, TaskStatus, LaunchInput, CompletionNotification, ParentModel, } from "./types";
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
* Minimal interfaces for fire-and-forget parallel agent execution
|
|
4
4
|
*/
|
|
5
5
|
export type TaskStatus = "running" | "completed" | "failed" | "cancelled";
|
|
6
|
+
export interface ParentModel {
|
|
7
|
+
providerID: string;
|
|
8
|
+
modelID: string;
|
|
9
|
+
}
|
|
6
10
|
export interface BackgroundTask {
|
|
7
11
|
id: string;
|
|
8
12
|
sessionID: string;
|
|
@@ -14,6 +18,7 @@ export interface BackgroundTask {
|
|
|
14
18
|
completedAt?: Date;
|
|
15
19
|
error?: string;
|
|
16
20
|
parentAgent?: string;
|
|
21
|
+
parentModel?: ParentModel;
|
|
17
22
|
}
|
|
18
23
|
export interface LaunchInput {
|
|
19
24
|
agent: string;
|
|
@@ -21,6 +26,7 @@ export interface LaunchInput {
|
|
|
21
26
|
description: string;
|
|
22
27
|
parentSessionID: string;
|
|
23
28
|
parentAgent?: string;
|
|
29
|
+
parentModel?: ParentModel;
|
|
24
30
|
}
|
|
25
31
|
export interface CompletionNotification {
|
|
26
32
|
allComplete: boolean;
|
|
@@ -28,4 +34,5 @@ export interface CompletionNotification {
|
|
|
28
34
|
completedTasks: BackgroundTask[];
|
|
29
35
|
runningCount: number;
|
|
30
36
|
parentAgent?: string;
|
|
37
|
+
parentModel?: ParentModel;
|
|
31
38
|
}
|
package/dist/index.js
CHANGED
|
@@ -822,6 +822,51 @@ The system automatically reminds you if you go idle with incomplete tasks.
|
|
|
822
822
|
- You have pending or in-progress todos
|
|
823
823
|
- The session goes idle
|
|
824
824
|
- There's been sufficient time since the last reminder
|
|
825
|
+
|
|
826
|
+
---
|
|
827
|
+
|
|
828
|
+
## Project Guidelines Auto-Documentation
|
|
829
|
+
|
|
830
|
+
You have \`save_project_guideline\` to keep AGENTS.md and CLAUDE.md automatically updated.
|
|
831
|
+
|
|
832
|
+
### When to Use
|
|
833
|
+
|
|
834
|
+
| Trigger | Example |
|
|
835
|
+
|---------|---------|
|
|
836
|
+
| User states a decision | "Always use Zustand", "We use Tailwind here" |
|
|
837
|
+
| You create reusable code | A utility function, hook, or pattern worth reusing |
|
|
838
|
+
| Architecture decision made | After analyzing options and choosing an approach |
|
|
839
|
+
| User corrects your approach | "No, do it this way instead" |
|
|
840
|
+
| Convention discovered | You notice a consistent pattern in the codebase |
|
|
841
|
+
|
|
842
|
+
### How to Use
|
|
843
|
+
|
|
844
|
+
1. **Read first**: Check AGENTS.md and CLAUDE.md to see if the info already exists
|
|
845
|
+
2. **If not there**: Call \`save_project_guideline({ content: "..." })\`
|
|
846
|
+
3. **The tool**: Appends to both files (or creates AGENTS.md if neither exists)
|
|
847
|
+
|
|
848
|
+
### Example
|
|
849
|
+
|
|
850
|
+
\`\`\`
|
|
851
|
+
// User says: "In this project, always use Zustand for state"
|
|
852
|
+
// 1. Read AGENTS.md - check if Zustand is mentioned
|
|
853
|
+
// 2. If not mentioned:
|
|
854
|
+
save_project_guideline({ content: "- State Management: Use Zustand, not Redux" })
|
|
855
|
+
\`\`\`
|
|
856
|
+
|
|
857
|
+
### What to Document
|
|
858
|
+
|
|
859
|
+
- Technology choices (frameworks, libraries, tools)
|
|
860
|
+
- Code patterns (how to structure components, API calls, etc.)
|
|
861
|
+
- Reusable utilities you create (hooks, helpers, formatters)
|
|
862
|
+
- Conventions (naming, folder structure, coding style)
|
|
863
|
+
- Important decisions that affect future work
|
|
864
|
+
|
|
865
|
+
### What NOT to Document
|
|
866
|
+
|
|
867
|
+
- One-off decisions ("use blue for this button")
|
|
868
|
+
- Things obvious from the code itself
|
|
869
|
+
- Temporary workarounds
|
|
825
870
|
`;
|
|
826
871
|
function getOrchestrationPrompt(agent) {
|
|
827
872
|
switch (agent) {
|
|
@@ -835,18 +880,26 @@ function getOrchestrationPrompt(agent) {
|
|
|
835
880
|
}
|
|
836
881
|
|
|
837
882
|
// src/orchestration/session-agent-tracker.ts
|
|
838
|
-
var
|
|
839
|
-
function
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
883
|
+
var sessionContextMap = new Map;
|
|
884
|
+
function setSessionContext(sessionID, context) {
|
|
885
|
+
const existing = sessionContextMap.get(sessionID) ?? {};
|
|
886
|
+
sessionContextMap.set(sessionID, {
|
|
887
|
+
agent: context.agent ?? existing.agent,
|
|
888
|
+
model: context.model ?? existing.model
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
function getSessionContext(sessionID) {
|
|
892
|
+
return sessionContextMap.get(sessionID);
|
|
843
893
|
}
|
|
844
894
|
function getSessionAgent(sessionID) {
|
|
845
|
-
return
|
|
895
|
+
return sessionContextMap.get(sessionID)?.agent;
|
|
896
|
+
}
|
|
897
|
+
function getSessionModel(sessionID) {
|
|
898
|
+
return sessionContextMap.get(sessionID)?.model;
|
|
846
899
|
}
|
|
847
900
|
function clearSessionAgent(sessionID) {
|
|
848
901
|
if (sessionID) {
|
|
849
|
-
|
|
902
|
+
sessionContextMap.delete(sessionID);
|
|
850
903
|
}
|
|
851
904
|
}
|
|
852
905
|
function getOrchestrationAgentType(agent) {
|
|
@@ -4995,7 +5048,8 @@ class BackgroundManager {
|
|
|
4995
5048
|
prompt: input.prompt,
|
|
4996
5049
|
status: "running",
|
|
4997
5050
|
startedAt: new Date,
|
|
4998
|
-
parentAgent: input.parentAgent
|
|
5051
|
+
parentAgent: input.parentAgent,
|
|
5052
|
+
parentModel: input.parentModel
|
|
4999
5053
|
};
|
|
5000
5054
|
this.tasks.set(task.id, task);
|
|
5001
5055
|
if (this.toastManager) {
|
|
@@ -5134,12 +5188,14 @@ ${runningTasks.length} task(s) still running. Continue working.
|
|
|
5134
5188
|
</system-reminder>`;
|
|
5135
5189
|
}
|
|
5136
5190
|
const parentAgent = completedTasks[0]?.parentAgent;
|
|
5191
|
+
const parentModel = completedTasks[0]?.parentModel;
|
|
5137
5192
|
return {
|
|
5138
5193
|
allComplete,
|
|
5139
5194
|
message,
|
|
5140
5195
|
completedTasks,
|
|
5141
5196
|
runningCount: runningTasks.length,
|
|
5142
|
-
parentAgent
|
|
5197
|
+
parentAgent,
|
|
5198
|
+
parentModel
|
|
5143
5199
|
};
|
|
5144
5200
|
}
|
|
5145
5201
|
listActiveTasks() {
|
|
@@ -17490,12 +17546,14 @@ Use for independent research tasks that benefit from parallelism.`,
|
|
|
17490
17546
|
},
|
|
17491
17547
|
async execute(args, context) {
|
|
17492
17548
|
try {
|
|
17549
|
+
const parentModel = getSessionModel(context.sessionID);
|
|
17493
17550
|
const task = await manager.launch(client, {
|
|
17494
17551
|
agent: args.agent,
|
|
17495
17552
|
description: args.description,
|
|
17496
17553
|
prompt: args.prompt,
|
|
17497
17554
|
parentSessionID: context.sessionID,
|
|
17498
|
-
parentAgent: context.agent
|
|
17555
|
+
parentAgent: context.agent,
|
|
17556
|
+
parentModel
|
|
17499
17557
|
});
|
|
17500
17558
|
const activeTasks = manager.listActiveTasks();
|
|
17501
17559
|
return `Background task launched successfully.
|
|
@@ -17930,12 +17988,15 @@ Current incomplete tasks:
|
|
|
17930
17988
|
${todoList}
|
|
17931
17989
|
|
|
17932
17990
|
${statusLine}`;
|
|
17933
|
-
const
|
|
17991
|
+
const sessionContext = getSessionContext(sessionID);
|
|
17992
|
+
const model = sessionContext?.model;
|
|
17993
|
+
const sendPrompt = async (omitContext = false) => {
|
|
17934
17994
|
await ctx.client.session.prompt({
|
|
17935
17995
|
path: { id: sessionID },
|
|
17936
17996
|
body: {
|
|
17937
17997
|
noReply: false,
|
|
17938
|
-
...
|
|
17998
|
+
...omitContext || !agent ? {} : { agent },
|
|
17999
|
+
...omitContext || !model ? {} : { model },
|
|
17939
18000
|
parts: [{ type: "text", text: prompt }]
|
|
17940
18001
|
}
|
|
17941
18002
|
});
|
|
@@ -17944,7 +18005,7 @@ ${statusLine}`;
|
|
|
17944
18005
|
await sendPrompt();
|
|
17945
18006
|
} catch (err) {
|
|
17946
18007
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
17947
|
-
if (errorMsg.includes("agent") || errorMsg.includes("undefined")) {
|
|
18008
|
+
if (errorMsg.includes("agent") || errorMsg.includes("model") || errorMsg.includes("undefined")) {
|
|
17948
18009
|
try {
|
|
17949
18010
|
await sendPrompt(true);
|
|
17950
18011
|
} catch {
|
|
@@ -18281,6 +18342,87 @@ Shows which LSP servers are running and their status.`,
|
|
|
18281
18342
|
lsp_status: lspStatus
|
|
18282
18343
|
};
|
|
18283
18344
|
}
|
|
18345
|
+
// src/tools/project-guidelines/tools.ts
|
|
18346
|
+
import * as fs2 from "fs/promises";
|
|
18347
|
+
import * as path2 from "path";
|
|
18348
|
+
var GUIDELINE_FILES = ["AGENTS.md", "CLAUDE.md"];
|
|
18349
|
+
async function fileExists(filePath) {
|
|
18350
|
+
try {
|
|
18351
|
+
await fs2.access(filePath);
|
|
18352
|
+
return true;
|
|
18353
|
+
} catch {
|
|
18354
|
+
return false;
|
|
18355
|
+
}
|
|
18356
|
+
}
|
|
18357
|
+
async function appendToFile(filePath, content) {
|
|
18358
|
+
const exists = await fileExists(filePath);
|
|
18359
|
+
if (exists) {
|
|
18360
|
+
const existing = await fs2.readFile(filePath, "utf-8");
|
|
18361
|
+
const separator = existing.endsWith(`
|
|
18362
|
+
`) ? "" : `
|
|
18363
|
+
`;
|
|
18364
|
+
await fs2.writeFile(filePath, existing + separator + content + `
|
|
18365
|
+
`);
|
|
18366
|
+
} else {
|
|
18367
|
+
await fs2.writeFile(filePath, content + `
|
|
18368
|
+
`);
|
|
18369
|
+
}
|
|
18370
|
+
}
|
|
18371
|
+
function createProjectGuidelinesTools(projectDir) {
|
|
18372
|
+
const saveProjectGuideline = tool({
|
|
18373
|
+
description: `Save important project decisions, patterns, or conventions to AGENTS.md and CLAUDE.md.
|
|
18374
|
+
Use this to document:
|
|
18375
|
+
- Important decisions (technology choices, architecture decisions)
|
|
18376
|
+
- Reusable code patterns or utilities you created
|
|
18377
|
+
- Conventions discovered or agreed upon
|
|
18378
|
+
- Guidelines that should persist across sessions
|
|
18379
|
+
|
|
18380
|
+
IMPORTANT: Before calling this tool, read AGENTS.md and CLAUDE.md first to check if the information already exists. Only call this tool if the guideline is NOT already documented.
|
|
18381
|
+
|
|
18382
|
+
The tool appends to both files if they exist, or creates AGENTS.md if neither exists.`,
|
|
18383
|
+
args: {
|
|
18384
|
+
content: tool.schema.string().describe("The guideline, decision, or pattern to document")
|
|
18385
|
+
},
|
|
18386
|
+
async execute(args) {
|
|
18387
|
+
try {
|
|
18388
|
+
const content = args.content.trim();
|
|
18389
|
+
if (!content) {
|
|
18390
|
+
return "Error: Content cannot be empty";
|
|
18391
|
+
}
|
|
18392
|
+
const updatedFiles = [];
|
|
18393
|
+
let createdFile = false;
|
|
18394
|
+
const existingFiles = [];
|
|
18395
|
+
for (const fileName of GUIDELINE_FILES) {
|
|
18396
|
+
const filePath = path2.join(projectDir, fileName);
|
|
18397
|
+
if (await fileExists(filePath)) {
|
|
18398
|
+
existingFiles.push(fileName);
|
|
18399
|
+
}
|
|
18400
|
+
}
|
|
18401
|
+
if (existingFiles.length === 0) {
|
|
18402
|
+
const agentsPath = path2.join(projectDir, "AGENTS.md");
|
|
18403
|
+
await appendToFile(agentsPath, content);
|
|
18404
|
+
updatedFiles.push("AGENTS.md");
|
|
18405
|
+
createdFile = true;
|
|
18406
|
+
} else {
|
|
18407
|
+
for (const fileName of existingFiles) {
|
|
18408
|
+
const filePath = path2.join(projectDir, fileName);
|
|
18409
|
+
await appendToFile(filePath, content);
|
|
18410
|
+
updatedFiles.push(fileName);
|
|
18411
|
+
}
|
|
18412
|
+
}
|
|
18413
|
+
const fileList = updatedFiles.join(" and ");
|
|
18414
|
+
const action = createdFile ? "Created" : "Updated";
|
|
18415
|
+
return `${action} ${fileList} with: "${content.substring(0, 100)}${content.length > 100 ? "..." : ""}"`;
|
|
18416
|
+
} catch (err) {
|
|
18417
|
+
const errorMsg = err instanceof Error ? err.message : "Unknown error";
|
|
18418
|
+
return `Failed to save guideline: ${errorMsg}`;
|
|
18419
|
+
}
|
|
18420
|
+
}
|
|
18421
|
+
});
|
|
18422
|
+
return {
|
|
18423
|
+
save_project_guideline: saveProjectGuideline
|
|
18424
|
+
};
|
|
18425
|
+
}
|
|
18284
18426
|
// src/shared/agent-variant.ts
|
|
18285
18427
|
function resolveAgentVariant(config2, agentName) {
|
|
18286
18428
|
if (!agentName)
|
|
@@ -18334,6 +18476,7 @@ var ZenoxPlugin = async (ctx) => {
|
|
|
18334
18476
|
const todoEnforcerHook = createTodoEnforcerHook(ctx);
|
|
18335
18477
|
const sessionTools = createSessionTools(ctx.client);
|
|
18336
18478
|
const codeIntelligenceTools = createCodeIntelligenceTools(ctx.client);
|
|
18479
|
+
const projectGuidelinesTools = createProjectGuidelinesTools(ctx.directory);
|
|
18337
18480
|
const firstMessageVariantGate = createFirstMessageVariantGate();
|
|
18338
18481
|
const applyModelOverride = (agentName, baseAgent) => {
|
|
18339
18482
|
const override = pluginConfig.agents?.[agentName];
|
|
@@ -18346,10 +18489,11 @@ var ZenoxPlugin = async (ctx) => {
|
|
|
18346
18489
|
tool: {
|
|
18347
18490
|
...backgroundTools,
|
|
18348
18491
|
...sessionTools,
|
|
18349
|
-
...codeIntelligenceTools
|
|
18492
|
+
...codeIntelligenceTools,
|
|
18493
|
+
...projectGuidelinesTools
|
|
18350
18494
|
},
|
|
18351
18495
|
"chat.message": async (input, output) => {
|
|
18352
|
-
|
|
18496
|
+
setSessionContext(input.sessionID, { agent: input.agent, model: input.model });
|
|
18353
18497
|
const message = output.message;
|
|
18354
18498
|
if (firstMessageVariantGate.shouldOverride(input.sessionID)) {
|
|
18355
18499
|
const variant = resolveAgentVariant(pluginConfig, input.agent);
|
|
@@ -18402,19 +18546,20 @@ var ZenoxPlugin = async (ctx) => {
|
|
|
18402
18546
|
if (notification) {
|
|
18403
18547
|
const mainSessionID = backgroundManager.getMainSession();
|
|
18404
18548
|
if (mainSessionID) {
|
|
18405
|
-
const sendNotification = async (
|
|
18549
|
+
const sendNotification = async (omitContext = false) => {
|
|
18406
18550
|
try {
|
|
18407
18551
|
await ctx.client.session.prompt({
|
|
18408
18552
|
path: { id: mainSessionID },
|
|
18409
18553
|
body: {
|
|
18410
18554
|
noReply: !notification.allComplete,
|
|
18411
|
-
...
|
|
18555
|
+
...omitContext ? {} : { agent: notification.parentAgent },
|
|
18556
|
+
...omitContext ? {} : { model: notification.parentModel },
|
|
18412
18557
|
parts: [{ type: "text", text: notification.message }]
|
|
18413
18558
|
}
|
|
18414
18559
|
});
|
|
18415
18560
|
} catch (err) {
|
|
18416
18561
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
18417
|
-
if (!
|
|
18562
|
+
if (!omitContext && (errorMsg.includes("agent") || errorMsg.includes("model") || errorMsg.includes("undefined"))) {
|
|
18418
18563
|
return sendNotification(true);
|
|
18419
18564
|
}
|
|
18420
18565
|
}
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* Orchestration prompt to inject into Build and Plan agents.
|
|
3
3
|
* This teaches the primary agents how to delegate to specialized subagents using the Task tool.
|
|
4
4
|
*/
|
|
5
|
-
export declare const ORCHESTRATION_PROMPT = "\n\n---\n\n## Sub-Agent Delegation\n\nYou have specialized subagents. Use the **Task tool** to delegate work proactively.\n\n### Available Agents\n\n| Agent | Use For | subagent_type |\n|-------|---------|---------------|\n| **Explorer** | Codebase grep - fast pattern matching, \"Where is X?\" | `explorer` |\n| **Librarian** | External grep - docs, GitHub, OSS examples | `librarian` |\n| **Oracle** | Strategic advisor - architecture, debugging, decisions | `oracle` |\n| **UI Planner** | Designer-developer - visual design, CSS, animations | `ui-planner` |\n\n### Quick Rule: Background vs Synchronous\n\n| Agent | Default Execution | Why |\n|-------|-------------------|-----|\n| Explorer | `background_task` | It's codebase grep - fire and continue |\n| Librarian | `background_task` | It's external grep - fire and continue |\n| Oracle | `Task` (sync) | Need strategic answer before proceeding |\n| UI Planner | `Task` (sync) | Implements changes, needs write access |\n\n**Mental Model**: Explorer & Librarian = **grep commands**. You don't wait for grep, you fire it and continue thinking.\n\n### When to Delegate (Fire Immediately)\n\n| Trigger | subagent_type | Why |\n|---------|---------------|-----|\n| \"Where is X?\", \"Find Y\", locate code | `explorer` | Fast codebase search |\n| External library, \"how does X library work?\" | `librarian` | Searches docs, GitHub, OSS |\n| 2+ modules involved, cross-cutting concerns | `explorer` | Multi-file pattern discovery |\n| Architecture decision, \"should I use X or Y?\" | `oracle` | Deep reasoning advisor |\n| Visual/styling, CSS, animations, UI/UX | `ui-planner` | Designer-developer hybrid |\n| After 2+ failed fix attempts | `oracle` | Debugging escalation |\n\n### How to Delegate\n\nUse the Task tool with these parameters:\n\n```\nTask(\n subagent_type: \"explorer\" | \"librarian\" | \"oracle\" | \"ui-planner\",\n description: \"Short 3-5 word task description\",\n prompt: \"Detailed instructions for the agent\"\n)\n```\n\n**Example delegations:**\n\n```\n// Find code in codebase\nTask(\n subagent_type: \"explorer\",\n description: \"Find auth middleware\",\n prompt: \"Find all authentication middleware implementations in this codebase. Return file paths and explain the auth flow.\"\n)\n\n// Research external library\nTask(\n subagent_type: \"librarian\",\n description: \"React Query caching docs\",\n prompt: \"How does React Query handle caching? Find official documentation and real-world examples with GitHub permalinks.\"\n)\n\n// Architecture decision\nTask(\n subagent_type: \"oracle\",\n description: \"Redux vs Zustand analysis\",\n prompt: \"Analyze trade-offs between Redux and Zustand for this project. Consider bundle size, learning curve, and our existing patterns.\"\n)\n\n// UI/Visual work\nTask(\n subagent_type: \"ui-planner\",\n description: \"Redesign dashboard cards\",\n prompt: \"Redesign the dashboard stat cards to be more visually appealing. Use modern aesthetics, subtle animations, and ensure responsive design.\"\n)\n```\n\n### Parallel Execution\n\nTo run multiple agents in parallel, call multiple Task tools in the **same response message**:\n\n```\n// CORRECT: Multiple Task calls in ONE message = parallel execution\nTask(subagent_type: \"explorer\", description: \"Find auth code\", prompt: \"...\")\nTask(subagent_type: \"librarian\", description: \"JWT best practices\", prompt: \"...\")\n// Both run simultaneously\n\n// WRONG: One Task per message = sequential (slow)\nMessage 1: Task(...) \u2192 wait for result\nMessage 2: Task(...) \u2192 wait for result\n```\n\n### Delegation Priority\n\n1. **Explorer FIRST** \u2014 Always locate code before modifying unfamiliar areas\n2. **Librarian** \u2014 When dealing with external libraries/APIs you don't fully understand\n3. **Oracle** \u2014 For complex decisions or after 2+ failed fix attempts\n4. **UI Planner** \u2014 For ANY visual/styling work (never edit CSS/UI yourself)\n\n### Critical Rules\n\n1. **Never touch frontend visual/styling code yourself** \u2014 Always delegate to `ui-planner`\n2. **Fire librarian proactively** when unfamiliar libraries are involved\n3. **Consult oracle BEFORE major architectural decisions**, not after\n4. **Verify delegated work** before marking task complete\n\n### When to Handle Directly (Don't Delegate)\n\n- Single file edits with known location\n- Questions answerable from code already in context\n- Trivial changes requiring no specialist knowledge\n- Tasks you can complete faster than explaining to an agent\n\n---\n\n## Background Tasks (Parallel Research)\n\nFor **independent research tasks** that benefit from parallelism, use background tasks instead of sequential Task calls.\n\n### When to Use Background Tasks\n\n| Scenario | Use Background Tasks |\n|----------|---------------------|\n| User wants \"comprehensive\" / \"thorough\" / \"deep\" exploration | YES - fire 3-4 agents in parallel |\n| Need BOTH codebase search AND external docs | YES - explore + librarian in parallel |\n| Exploring multiple modules/features simultaneously | YES - separate explore for each |\n| Result of Task A needed before Task B | NO - use sequential Task |\n| Single focused lookup | NO - just use Task directly |\n\n### How Background Tasks Work\n\n1. **Fire**: Launch multiple agents with `background_task` - they run in parallel\n2. **Continue**: Keep working while background agents search\n3. **Notify**: You'll be notified when ALL background tasks complete\n4. **Retrieve**: Use `background_output` to get each result\n\n### Usage\n\n```\n// Launch parallel research (all run simultaneously)\nbackground_task(agent=\"explorer\", description=\"Find auth code\", prompt=\"Search for authentication...\")\nbackground_task(agent=\"explorer\", description=\"Find db layer\", prompt=\"Search for database/ORM...\")\nbackground_task(agent=\"librarian\", description=\"Best practices\", prompt=\"Find framework best practices...\")\n\n// Continue working on other things while they run...\n\n// [NOTIFICATION: All background tasks complete!]\n\n// Retrieve results\nbackground_output(task_id=\"bg_abc123\")\nbackground_output(task_id=\"bg_def456\")\nbackground_output(task_id=\"bg_ghi789\")\n```\n\n### Background Tasks vs Task Tool\n\n| Aspect | Task Tool | Background Tasks |\n|--------|-----------|------------------|\n| Execution | Sequential (waits for result) | Parallel (fire-and-forget) |\n| Best for | Dependent tasks, immediate needs | Independent research, breadth |\n| Result | Inline, immediate | Retrieved later via background_output |\n\n### Key Insight\n\n- **Task** = Use when you need the result immediately before proceeding\n- **Background** = Use when researching multiple angles independently\n\n**Both tools coexist - choose based on whether tasks are dependent or independent.**\n\n### The Parallel Research Pattern\n\nFor complex tasks, fire research first, then continue working:\n\n```\n// 1. FIRE parallel research (don't wait!)\nbackground_task(agent=\"explorer\", description=\"Find existing patterns\", prompt=\"...\")\nbackground_task(agent=\"librarian\", description=\"Find best practices\", prompt=\"...\")\n\n// 2. CONTINUE productive work while they run:\n// - Plan your implementation approach\n// - Read files you already know about\n// - Identify edge cases and questions\n\n// 3. When notified \u2192 RETRIEVE and synthesize\nbackground_output(task_id=\"bg_xxx\")\nbackground_output(task_id=\"bg_yyy\")\n```\n\n**Anti-pattern**: Firing background tasks then doing nothing. Always continue productive work!\n\n---\n\n## Keyword Triggers (Power User)\n\nInclude these keywords in your prompt to unlock special modes:\n\n| Keyword | Effect |\n|---------|--------|\n| `ultrawork` or `ulw` | Maximum multi-agent coordination - aggressive parallel research |\n| `deep research` | Comprehensive exploration - fires 3-4 background agents |\n| `explore codebase` | Codebase mapping - multiple explorers in parallel |\n\n---\n\n## Session History Tools\n\nYou have tools to learn from past work sessions:\n\n| Tool | Use For |\n|------|---------|\n| `session_list` | List recent sessions to find relevant past work |\n| `session_search` | Search messages across sessions for how something was done |\n\n### When to Use Session Tools\n\n- **Before implementing unfamiliar features** \u2014 search if done before\n- **When user says \"like before\" or \"last time\"** \u2014 find that session\n- **When debugging** \u2014 check if similar issues were solved previously\n- **For context on ongoing projects** \u2014 understand recent work history\n\n### Example Usage\n\n```\n// Find how authentication was implemented before\nsession_search({ query: \"JWT authentication\" })\n\n// List recent sessions to understand project context\nsession_list({ limit: 5 })\n\n// Find past implementations of a feature\nsession_search({ query: \"rate limiting\" })\n```\n\n---\n\n## Code Intelligence Tools\n\nYou have tools to understand code structure via LSP:\n\n| Tool | Use For |\n|------|---------|\n| `find_symbols` | Search for functions, classes, variables by name |\n| `lsp_status` | Check which language servers are running |\n\n### When to Use Code Intelligence\n\n- **Before editing code** \u2014 find the symbol's definition location\n- **When refactoring** \u2014 search for related symbols\n- **To understand project structure** \u2014 search for key symbols like \"auth\", \"user\", \"api\"\n- **To verify LSP availability** \u2014 check if code intelligence is working\n\n### Example Usage\n\n```\n// Find all auth-related functions/classes\nfind_symbols({ query: \"auth\" })\n\n// Find a specific function\nfind_symbols({ query: \"handleLogin\" })\n\n// Check LSP server status\nlsp_status()\n```\n\n---\n\n## Todo Continuation\n\nThe system automatically reminds you if you go idle with incomplete tasks.\n\n**Best Practices:**\n- Keep your todo list updated with `TodoWrite`\n- Mark tasks complete immediately when finished\n- Use clear, actionable task descriptions\n- The system will prompt you to continue if tasks remain incomplete\n\n**Note:** You don't need to invoke the todo enforcer \u2014 it runs automatically when:\n- You have pending or in-progress todos\n- The session goes idle\n- There's been sufficient time since the last reminder\n";
|
|
5
|
+
export declare const ORCHESTRATION_PROMPT = "\n\n---\n\n## Sub-Agent Delegation\n\nYou have specialized subagents. Use the **Task tool** to delegate work proactively.\n\n### Available Agents\n\n| Agent | Use For | subagent_type |\n|-------|---------|---------------|\n| **Explorer** | Codebase grep - fast pattern matching, \"Where is X?\" | `explorer` |\n| **Librarian** | External grep - docs, GitHub, OSS examples | `librarian` |\n| **Oracle** | Strategic advisor - architecture, debugging, decisions | `oracle` |\n| **UI Planner** | Designer-developer - visual design, CSS, animations | `ui-planner` |\n\n### Quick Rule: Background vs Synchronous\n\n| Agent | Default Execution | Why |\n|-------|-------------------|-----|\n| Explorer | `background_task` | It's codebase grep - fire and continue |\n| Librarian | `background_task` | It's external grep - fire and continue |\n| Oracle | `Task` (sync) | Need strategic answer before proceeding |\n| UI Planner | `Task` (sync) | Implements changes, needs write access |\n\n**Mental Model**: Explorer & Librarian = **grep commands**. You don't wait for grep, you fire it and continue thinking.\n\n### When to Delegate (Fire Immediately)\n\n| Trigger | subagent_type | Why |\n|---------|---------------|-----|\n| \"Where is X?\", \"Find Y\", locate code | `explorer` | Fast codebase search |\n| External library, \"how does X library work?\" | `librarian` | Searches docs, GitHub, OSS |\n| 2+ modules involved, cross-cutting concerns | `explorer` | Multi-file pattern discovery |\n| Architecture decision, \"should I use X or Y?\" | `oracle` | Deep reasoning advisor |\n| Visual/styling, CSS, animations, UI/UX | `ui-planner` | Designer-developer hybrid |\n| After 2+ failed fix attempts | `oracle` | Debugging escalation |\n\n### How to Delegate\n\nUse the Task tool with these parameters:\n\n```\nTask(\n subagent_type: \"explorer\" | \"librarian\" | \"oracle\" | \"ui-planner\",\n description: \"Short 3-5 word task description\",\n prompt: \"Detailed instructions for the agent\"\n)\n```\n\n**Example delegations:**\n\n```\n// Find code in codebase\nTask(\n subagent_type: \"explorer\",\n description: \"Find auth middleware\",\n prompt: \"Find all authentication middleware implementations in this codebase. Return file paths and explain the auth flow.\"\n)\n\n// Research external library\nTask(\n subagent_type: \"librarian\",\n description: \"React Query caching docs\",\n prompt: \"How does React Query handle caching? Find official documentation and real-world examples with GitHub permalinks.\"\n)\n\n// Architecture decision\nTask(\n subagent_type: \"oracle\",\n description: \"Redux vs Zustand analysis\",\n prompt: \"Analyze trade-offs between Redux and Zustand for this project. Consider bundle size, learning curve, and our existing patterns.\"\n)\n\n// UI/Visual work\nTask(\n subagent_type: \"ui-planner\",\n description: \"Redesign dashboard cards\",\n prompt: \"Redesign the dashboard stat cards to be more visually appealing. Use modern aesthetics, subtle animations, and ensure responsive design.\"\n)\n```\n\n### Parallel Execution\n\nTo run multiple agents in parallel, call multiple Task tools in the **same response message**:\n\n```\n// CORRECT: Multiple Task calls in ONE message = parallel execution\nTask(subagent_type: \"explorer\", description: \"Find auth code\", prompt: \"...\")\nTask(subagent_type: \"librarian\", description: \"JWT best practices\", prompt: \"...\")\n// Both run simultaneously\n\n// WRONG: One Task per message = sequential (slow)\nMessage 1: Task(...) \u2192 wait for result\nMessage 2: Task(...) \u2192 wait for result\n```\n\n### Delegation Priority\n\n1. **Explorer FIRST** \u2014 Always locate code before modifying unfamiliar areas\n2. **Librarian** \u2014 When dealing with external libraries/APIs you don't fully understand\n3. **Oracle** \u2014 For complex decisions or after 2+ failed fix attempts\n4. **UI Planner** \u2014 For ANY visual/styling work (never edit CSS/UI yourself)\n\n### Critical Rules\n\n1. **Never touch frontend visual/styling code yourself** \u2014 Always delegate to `ui-planner`\n2. **Fire librarian proactively** when unfamiliar libraries are involved\n3. **Consult oracle BEFORE major architectural decisions**, not after\n4. **Verify delegated work** before marking task complete\n\n### When to Handle Directly (Don't Delegate)\n\n- Single file edits with known location\n- Questions answerable from code already in context\n- Trivial changes requiring no specialist knowledge\n- Tasks you can complete faster than explaining to an agent\n\n---\n\n## Background Tasks (Parallel Research)\n\nFor **independent research tasks** that benefit from parallelism, use background tasks instead of sequential Task calls.\n\n### When to Use Background Tasks\n\n| Scenario | Use Background Tasks |\n|----------|---------------------|\n| User wants \"comprehensive\" / \"thorough\" / \"deep\" exploration | YES - fire 3-4 agents in parallel |\n| Need BOTH codebase search AND external docs | YES - explore + librarian in parallel |\n| Exploring multiple modules/features simultaneously | YES - separate explore for each |\n| Result of Task A needed before Task B | NO - use sequential Task |\n| Single focused lookup | NO - just use Task directly |\n\n### How Background Tasks Work\n\n1. **Fire**: Launch multiple agents with `background_task` - they run in parallel\n2. **Continue**: Keep working while background agents search\n3. **Notify**: You'll be notified when ALL background tasks complete\n4. **Retrieve**: Use `background_output` to get each result\n\n### Usage\n\n```\n// Launch parallel research (all run simultaneously)\nbackground_task(agent=\"explorer\", description=\"Find auth code\", prompt=\"Search for authentication...\")\nbackground_task(agent=\"explorer\", description=\"Find db layer\", prompt=\"Search for database/ORM...\")\nbackground_task(agent=\"librarian\", description=\"Best practices\", prompt=\"Find framework best practices...\")\n\n// Continue working on other things while they run...\n\n// [NOTIFICATION: All background tasks complete!]\n\n// Retrieve results\nbackground_output(task_id=\"bg_abc123\")\nbackground_output(task_id=\"bg_def456\")\nbackground_output(task_id=\"bg_ghi789\")\n```\n\n### Background Tasks vs Task Tool\n\n| Aspect | Task Tool | Background Tasks |\n|--------|-----------|------------------|\n| Execution | Sequential (waits for result) | Parallel (fire-and-forget) |\n| Best for | Dependent tasks, immediate needs | Independent research, breadth |\n| Result | Inline, immediate | Retrieved later via background_output |\n\n### Key Insight\n\n- **Task** = Use when you need the result immediately before proceeding\n- **Background** = Use when researching multiple angles independently\n\n**Both tools coexist - choose based on whether tasks are dependent or independent.**\n\n### The Parallel Research Pattern\n\nFor complex tasks, fire research first, then continue working:\n\n```\n// 1. FIRE parallel research (don't wait!)\nbackground_task(agent=\"explorer\", description=\"Find existing patterns\", prompt=\"...\")\nbackground_task(agent=\"librarian\", description=\"Find best practices\", prompt=\"...\")\n\n// 2. CONTINUE productive work while they run:\n// - Plan your implementation approach\n// - Read files you already know about\n// - Identify edge cases and questions\n\n// 3. When notified \u2192 RETRIEVE and synthesize\nbackground_output(task_id=\"bg_xxx\")\nbackground_output(task_id=\"bg_yyy\")\n```\n\n**Anti-pattern**: Firing background tasks then doing nothing. Always continue productive work!\n\n---\n\n## Keyword Triggers (Power User)\n\nInclude these keywords in your prompt to unlock special modes:\n\n| Keyword | Effect |\n|---------|--------|\n| `ultrawork` or `ulw` | Maximum multi-agent coordination - aggressive parallel research |\n| `deep research` | Comprehensive exploration - fires 3-4 background agents |\n| `explore codebase` | Codebase mapping - multiple explorers in parallel |\n\n---\n\n## Session History Tools\n\nYou have tools to learn from past work sessions:\n\n| Tool | Use For |\n|------|---------|\n| `session_list` | List recent sessions to find relevant past work |\n| `session_search` | Search messages across sessions for how something was done |\n\n### When to Use Session Tools\n\n- **Before implementing unfamiliar features** \u2014 search if done before\n- **When user says \"like before\" or \"last time\"** \u2014 find that session\n- **When debugging** \u2014 check if similar issues were solved previously\n- **For context on ongoing projects** \u2014 understand recent work history\n\n### Example Usage\n\n```\n// Find how authentication was implemented before\nsession_search({ query: \"JWT authentication\" })\n\n// List recent sessions to understand project context\nsession_list({ limit: 5 })\n\n// Find past implementations of a feature\nsession_search({ query: \"rate limiting\" })\n```\n\n---\n\n## Code Intelligence Tools\n\nYou have tools to understand code structure via LSP:\n\n| Tool | Use For |\n|------|---------|\n| `find_symbols` | Search for functions, classes, variables by name |\n| `lsp_status` | Check which language servers are running |\n\n### When to Use Code Intelligence\n\n- **Before editing code** \u2014 find the symbol's definition location\n- **When refactoring** \u2014 search for related symbols\n- **To understand project structure** \u2014 search for key symbols like \"auth\", \"user\", \"api\"\n- **To verify LSP availability** \u2014 check if code intelligence is working\n\n### Example Usage\n\n```\n// Find all auth-related functions/classes\nfind_symbols({ query: \"auth\" })\n\n// Find a specific function\nfind_symbols({ query: \"handleLogin\" })\n\n// Check LSP server status\nlsp_status()\n```\n\n---\n\n## Todo Continuation\n\nThe system automatically reminds you if you go idle with incomplete tasks.\n\n**Best Practices:**\n- Keep your todo list updated with `TodoWrite`\n- Mark tasks complete immediately when finished\n- Use clear, actionable task descriptions\n- The system will prompt you to continue if tasks remain incomplete\n\n**Note:** You don't need to invoke the todo enforcer \u2014 it runs automatically when:\n- You have pending or in-progress todos\n- The session goes idle\n- There's been sufficient time since the last reminder\n\n---\n\n## Project Guidelines Auto-Documentation\n\nYou have `save_project_guideline` to keep AGENTS.md and CLAUDE.md automatically updated.\n\n### When to Use\n\n| Trigger | Example |\n|---------|---------|\n| User states a decision | \"Always use Zustand\", \"We use Tailwind here\" |\n| You create reusable code | A utility function, hook, or pattern worth reusing |\n| Architecture decision made | After analyzing options and choosing an approach |\n| User corrects your approach | \"No, do it this way instead\" |\n| Convention discovered | You notice a consistent pattern in the codebase |\n\n### How to Use\n\n1. **Read first**: Check AGENTS.md and CLAUDE.md to see if the info already exists\n2. **If not there**: Call `save_project_guideline({ content: \"...\" })`\n3. **The tool**: Appends to both files (or creates AGENTS.md if neither exists)\n\n### Example\n\n```\n// User says: \"In this project, always use Zustand for state\"\n// 1. Read AGENTS.md - check if Zustand is mentioned\n// 2. If not mentioned:\nsave_project_guideline({ content: \"- State Management: Use Zustand, not Redux\" })\n```\n\n### What to Document\n\n- Technology choices (frameworks, libraries, tools)\n- Code patterns (how to structure components, API calls, etc.)\n- Reusable utilities you create (hooks, helpers, formatters)\n- Conventions (naming, folder structure, coding style)\n- Important decisions that affect future work\n\n### What NOT to Document\n\n- One-off decisions (\"use blue for this button\")\n- Things obvious from the code itself\n- Temporary workarounds\n";
|
|
6
6
|
export declare function getOrchestrationPrompt(agent: "build" | "plan" | string | undefined): string | undefined;
|
|
@@ -1,17 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Session
|
|
2
|
+
* Session Context Tracker
|
|
3
3
|
*
|
|
4
|
-
* Tracks
|
|
5
|
-
* hook to inject agent-specific prompts
|
|
4
|
+
* Tracks agent and model context for each session, allowing:
|
|
5
|
+
* - System transform hook to inject agent-specific prompts
|
|
6
|
+
* - Todo enforcer and background tasks to preserve model context
|
|
6
7
|
*
|
|
7
8
|
* Flow:
|
|
8
|
-
* 1. chat.message hook fires with { sessionID, agent }
|
|
9
|
-
* 2. We store the mapping: sessionID ->
|
|
9
|
+
* 1. chat.message hook fires with { sessionID, agent, model }
|
|
10
|
+
* 2. We store the mapping: sessionID -> { agent, model }
|
|
10
11
|
* 3. experimental.chat.system.transform fires with { sessionID }
|
|
11
|
-
* 4. We look up the
|
|
12
|
+
* 4. We look up the context and inject the appropriate prompt
|
|
13
|
+
* 5. Todo enforcer / background tasks use model context when sending prompts
|
|
12
14
|
*/
|
|
15
|
+
export interface SessionModel {
|
|
16
|
+
providerID: string;
|
|
17
|
+
modelID: string;
|
|
18
|
+
}
|
|
19
|
+
export interface SessionContext {
|
|
20
|
+
agent?: string;
|
|
21
|
+
model?: SessionModel;
|
|
22
|
+
}
|
|
13
23
|
/**
|
|
14
|
-
* Record
|
|
24
|
+
* Record context (agent + model) for a session.
|
|
25
|
+
* Called from chat.message hook.
|
|
26
|
+
*/
|
|
27
|
+
export declare function setSessionContext(sessionID: string, context: {
|
|
28
|
+
agent?: string;
|
|
29
|
+
model?: SessionModel;
|
|
30
|
+
}): void;
|
|
31
|
+
/**
|
|
32
|
+
* Get the full context for a session.
|
|
33
|
+
*/
|
|
34
|
+
export declare function getSessionContext(sessionID: string): SessionContext | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Record which agent is active for a session (legacy helper).
|
|
15
37
|
* Called from chat.message hook.
|
|
16
38
|
*/
|
|
17
39
|
export declare function setSessionAgent(sessionID: string, agent: string | undefined): void;
|
|
@@ -20,6 +42,10 @@ export declare function setSessionAgent(sessionID: string, agent: string | undef
|
|
|
20
42
|
* Called from experimental.chat.system.transform hook.
|
|
21
43
|
*/
|
|
22
44
|
export declare function getSessionAgent(sessionID: string): string | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Get the active model for a session.
|
|
47
|
+
*/
|
|
48
|
+
export declare function getSessionModel(sessionID: string): SessionModel | undefined;
|
|
23
49
|
/**
|
|
24
50
|
* Clear tracking for a session (on deletion).
|
|
25
51
|
*/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createProjectGuidelinesTools, type ProjectGuidelinesTools, } from "./tools";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Guidelines Tools
|
|
3
|
+
*
|
|
4
|
+
* Auto-update AGENTS.md and CLAUDE.md with important decisions,
|
|
5
|
+
* patterns, and conventions discovered during development.
|
|
6
|
+
*/
|
|
7
|
+
import { type ToolDefinition } from "@opencode-ai/plugin";
|
|
8
|
+
export type ProjectGuidelinesTools = {
|
|
9
|
+
[key: string]: ToolDefinition;
|
|
10
|
+
};
|
|
11
|
+
export declare function createProjectGuidelinesTools(projectDir: string): ProjectGuidelinesTools;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zenox",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "OpenCode plugin with specialized agents (explorer, librarian, oracle, ui-planner), background tasks for parallel execution, and smart orchestration",
|
|
5
5
|
"author": "Ayush",
|
|
6
6
|
"license": "MIT",
|
|
@@ -46,6 +46,8 @@
|
|
|
46
46
|
"todo-enforcer",
|
|
47
47
|
"thinking-modes",
|
|
48
48
|
"variants",
|
|
49
|
+
"project-guidelines",
|
|
50
|
+
"auto-documentation",
|
|
49
51
|
"ai",
|
|
50
52
|
"llm",
|
|
51
53
|
"cli"
|