daemora 1.0.9 → 1.0.11
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 +37 -15
- package/SOUL.md +23 -4
- package/daemora-ui/dist/assets/index-BkPHvKYt.css +1 -0
- package/daemora-ui/dist/assets/index-ZiuOJUu0.js +92 -0
- package/daemora-ui/dist/index.html +2 -2
- package/package.json +1 -1
- package/skills/coding.md +23 -4
- package/skills/planning.md +168 -0
- package/src/agents/systemPrompt.js +80 -58
- package/src/cli.js +124 -4
- package/src/index.js +55 -15
- package/src/safety/CommandGuard.js +22 -1
- package/src/setup/theme.js +1 -0
- package/src/setup/wizard.js +220 -26
- package/src/tenants/TenantManager.js +37 -0
- package/src/tools/_paths.js +39 -0
- package/src/tools/applyPatch.js +6 -0
- package/src/tools/browserAutomation.js +18 -6
- package/src/tools/createDocument.js +4 -0
- package/src/tools/executeCommand.js +4 -2
- package/src/tools/generateImage.js +7 -3
- package/src/tools/replyWithFile.js +4 -0
- package/src/tools/screenCapture.js +6 -1
- package/src/tools/sendFile.js +4 -0
- package/src/tools/sshTool.js +2 -2
- package/src/tools/textToSpeech.js +21 -12
- package/src/tools/transcribeAudio.js +15 -4
- package/daemora-ui/dist/assets/index-AfA65HSy.js +0 -90
- package/daemora-ui/dist/assets/index-DP95eMOr.css +0 -1
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
<meta name="theme-color" content="#0a0a0f" />
|
|
8
8
|
<meta name="description" content="Daemora — Self-hosted AI agent platform" />
|
|
9
9
|
<title>Daemora</title>
|
|
10
|
-
<script type="module" crossorigin src="/assets/index-
|
|
11
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
10
|
+
<script type="module" crossorigin src="/assets/index-ZiuOJUu0.js"></script>
|
|
11
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BkPHvKYt.css">
|
|
12
12
|
</head>
|
|
13
13
|
<body>
|
|
14
14
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "daemora",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"description": "A powerful open-source AI agent that runs on your machine. Connects to any AI model, any MCP server, any channel. Fully autonomous - plans, codes, tests, browses, emails, and manages your tools without asking permission.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
package/skills/coding.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: coding
|
|
3
3
|
description: Use when writing, debugging, or reviewing code
|
|
4
|
-
triggers: code, function, bug, error, refactor, implement, class, module, typescript, javascript, python, api, endpoint, test, debug, fix, PR, pull request, commit, git
|
|
4
|
+
triggers: code, function, bug, error, refactor, implement, class, module, typescript, javascript, python, api, endpoint, test, debug, fix, PR, pull request, commit, git, push, pull, branch, merge, rebase, cherry-pick, stash, diff, log
|
|
5
5
|
---
|
|
6
6
|
## Workflow: Read → Understand → Change → Verify → Test
|
|
7
7
|
|
|
@@ -19,9 +19,28 @@ triggers: code, function, bug, error, refactor, implement, class, module, typesc
|
|
|
19
19
|
- Security: no injection, XSS, hardcoded secrets, path traversal
|
|
20
20
|
|
|
21
21
|
## Git Workflow
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
-
|
|
22
|
+
|
|
23
|
+
### Safety
|
|
24
|
+
- Never push without explicit user approval.
|
|
25
|
+
- Never force push. Never `reset --hard` without asking.
|
|
26
|
+
- Check current branch before committing — warn if on main/master.
|
|
27
|
+
- Never commit .env, credentials, or secrets.
|
|
28
|
+
|
|
29
|
+
### Commits
|
|
30
|
+
- `git diff` — review all changes before staging.
|
|
31
|
+
- Stage specific files — avoid `git add .` (catches unwanted files).
|
|
32
|
+
- Commit message: imperative, present tense, explain WHY not WHAT.
|
|
33
|
+
- One logical change per commit. Don't batch unrelated work.
|
|
34
|
+
|
|
35
|
+
### Branches
|
|
36
|
+
- Feature work → create a branch first. Don't commit directly to main.
|
|
37
|
+
- `git status` before switching branches — stash or commit dirty work.
|
|
38
|
+
- Pull before push — avoid conflicts.
|
|
39
|
+
|
|
40
|
+
### Pull Requests
|
|
41
|
+
- Title: short (<70 chars). Body: what changed and why.
|
|
42
|
+
- Reference related issues if applicable.
|
|
43
|
+
- Run tests before creating PR.
|
|
25
44
|
|
|
26
45
|
## Code Review
|
|
27
46
|
- Check for bugs, security issues, performance problems
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: planning
|
|
3
|
+
description: Task planning for any complex work — coding, research, communication, automation. Decide when to plan vs just do, break into steps, get user confirmation before executing.
|
|
4
|
+
triggers: plan, planning, design, architect, approach, strategy, implement, big task, complex task, multi-step, think through, break down, figure out, how should, what approach, steps, workflow
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Planning — Think Before You Act
|
|
8
|
+
|
|
9
|
+
## When to Plan vs Just Do It
|
|
10
|
+
|
|
11
|
+
**Plan first** when ANY of these apply:
|
|
12
|
+
- **Multiple steps required** — the task needs 3+ distinct actions to complete.
|
|
13
|
+
- **Multiple valid approaches** — the task can be solved several ways. Pick the right one first.
|
|
14
|
+
- **Unclear scope** — you need to explore or research before understanding the full extent of work.
|
|
15
|
+
- **User preferences matter** — the outcome could go multiple reasonable directions.
|
|
16
|
+
- **High stakes** — mistakes are costly to undo (emails sent, files restructured, data transformed).
|
|
17
|
+
- **Multi-agent work** — the task needs parallel or sequential agent coordination.
|
|
18
|
+
- **New feature or system change** — adding meaningful new functionality or modifying existing behavior.
|
|
19
|
+
- **Multi-file code changes** — the task will touch 3+ files. Map out which files and what changes.
|
|
20
|
+
- **Architectural decisions** — choosing between patterns, libraries, data models, or technologies.
|
|
21
|
+
|
|
22
|
+
**Skip planning** — do it directly:
|
|
23
|
+
- Single-action tasks (send one email, fetch one page, fix a typo).
|
|
24
|
+
- Tasks where the user gave very specific, detailed instructions.
|
|
25
|
+
- Quick lookups, simple questions, casual conversation.
|
|
26
|
+
- Few-line code fixes with obvious solutions.
|
|
27
|
+
|
|
28
|
+
**When in doubt → plan.** The cost of planning is low. The cost of rework is high.
|
|
29
|
+
|
|
30
|
+
## Planning Workflow
|
|
31
|
+
|
|
32
|
+
1. **Explore** — gather context. Read files, search the web, check memory, review conversation history. Understand the current state before deciding what to change.
|
|
33
|
+
2. **Identify the approach** — what needs to happen, in what order, using what tools/agents. Consider alternatives and pick the best one.
|
|
34
|
+
3. **Break into steps** — ordered list of concrete actions. Each step = one verifiable outcome. Keep it short — a list of actions, not an essay.
|
|
35
|
+
4. **Present the plan to the user** — before executing, tell the user what you're about to do and ask for confirmation. This prevents wasted effort and ensures alignment. Format: numbered list of concrete actions, not vague descriptions.
|
|
36
|
+
5. **Execute on confirmation** — work through each step. Verify after each one.
|
|
37
|
+
|
|
38
|
+
## User Confirmation
|
|
39
|
+
|
|
40
|
+
**Always confirm before executing a complex plan.** Present the plan clearly and ask:
|
|
41
|
+
- "Here's my plan — want me to go ahead?"
|
|
42
|
+
- List the concrete steps so the user can see what will happen.
|
|
43
|
+
- If the user adjusts, update the plan and confirm again.
|
|
44
|
+
- Only skip confirmation for simple tasks that don't need planning.
|
|
45
|
+
|
|
46
|
+
This is non-negotiable for complex work. The user should always know what's about to happen before it happens.
|
|
47
|
+
|
|
48
|
+
## Exploration by Task Type
|
|
49
|
+
|
|
50
|
+
**Code tasks:**
|
|
51
|
+
- Find files — `glob("src/**/*.ts")`, `searchFiles("*.controller.*")` to map the structure.
|
|
52
|
+
- Find patterns — `searchContent("export function", "src/")`, `grep("interface.*Props")` to see conventions.
|
|
53
|
+
- Read key files — entry points, related components, tests, configs.
|
|
54
|
+
- Check dependencies — what libraries, APIs, patterns are established.
|
|
55
|
+
|
|
56
|
+
**Research tasks:**
|
|
57
|
+
- Web search for current information on the topic.
|
|
58
|
+
- Fetch and read actual pages — don't stop at summaries.
|
|
59
|
+
- Check memory for previous findings on the same topic.
|
|
60
|
+
- Cross-reference multiple sources for anything important.
|
|
61
|
+
|
|
62
|
+
**Communication tasks:**
|
|
63
|
+
- Review conversation history for context and tone.
|
|
64
|
+
- Check memory for user preferences (writing style, contacts, templates).
|
|
65
|
+
- Identify all recipients, attachments, and follow-up actions needed.
|
|
66
|
+
|
|
67
|
+
**Automation / workflow tasks:**
|
|
68
|
+
- Map the full workflow end-to-end before automating any step.
|
|
69
|
+
- Identify dependencies between steps.
|
|
70
|
+
- Check what tools, APIs, and MCP servers are available.
|
|
71
|
+
|
|
72
|
+
3-5 targeted explorations is usually enough. Get the lay of the land, then plan.
|
|
73
|
+
|
|
74
|
+
## What a Good Plan Looks Like
|
|
75
|
+
|
|
76
|
+
A plan is a short ordered list of concrete actions:
|
|
77
|
+
|
|
78
|
+
**Coding example:**
|
|
79
|
+
```
|
|
80
|
+
1. Add FooService class in src/services/foo.ts — handles X with methods Y, Z
|
|
81
|
+
2. Update src/routes/api.ts — add GET /api/foo endpoint, wire to FooService
|
|
82
|
+
3. Add tests in tests/foo.test.ts — cover happy path + error cases
|
|
83
|
+
4. Run build + tests, fix any failures
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Research example:**
|
|
87
|
+
```
|
|
88
|
+
1. Search web for latest pricing on X, Y, Z services
|
|
89
|
+
2. Fetch each provider's pricing page, extract plan details
|
|
90
|
+
3. Compare features and costs in a structured table
|
|
91
|
+
4. Save findings to memory for future reference
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**Workflow example:**
|
|
95
|
+
```
|
|
96
|
+
1. Fetch all invoices from email (last 30 days)
|
|
97
|
+
2. Extract amounts, dates, vendors from each
|
|
98
|
+
3. Create summary spreadsheet in workspace
|
|
99
|
+
4. Send summary to user via email
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
NOT:
|
|
103
|
+
```
|
|
104
|
+
First, I'll think about what to do. Then I'll consider the options.
|
|
105
|
+
After that, I'll figure out the best approach. Finally, I'll do everything.
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Each step should be specific enough to hand to someone with zero context.
|
|
109
|
+
|
|
110
|
+
## Planning Multi-Agent Work
|
|
111
|
+
|
|
112
|
+
Any task that spawns agents — `spawnAgent`, `parallelAgents`, `useMCP` — is multi-agent work. MCP tasks are spawned agent tasks. Plan them the same way.
|
|
113
|
+
|
|
114
|
+
### Agent Isolation — Non-Negotiable
|
|
115
|
+
- Each agent operates in its own context. No shared memory, no shared state, no implicit communication.
|
|
116
|
+
- Agents must NOT touch files, paths, or resources owned by another agent. Define boundaries upfront.
|
|
117
|
+
- If two agents need the same data, pass it explicitly via `sharedContext` or workspace files. Never assume one agent can read another's output unless the plan says so.
|
|
118
|
+
- MCP agents (`useMCP`) get ONLY that server's tools. They cannot access files, shell, or other MCP servers. Plan accordingly — don't expect an MCP agent to do something outside its server's scope.
|
|
119
|
+
|
|
120
|
+
### Contract-Based Planning
|
|
121
|
+
Before spawning any agents, define the contract:
|
|
122
|
+
1. **Inputs** — what each agent receives. Exact data, file paths, specs. Paste the actual content into the brief — don't reference it.
|
|
123
|
+
2. **Outputs** — what each agent produces. File paths, data shapes, expected format.
|
|
124
|
+
3. **Boundaries** — what each agent is NOT allowed to touch. Files, directories, APIs outside its scope.
|
|
125
|
+
4. **Dependencies** — does agent B need output from agent A? Yes → sequential. No → parallel.
|
|
126
|
+
5. **Profiles** — coder for code, researcher for research, writer for docs, analyst for data.
|
|
127
|
+
|
|
128
|
+
### MCP as Spawned Agents
|
|
129
|
+
- `useMCP(serverName, taskDescription)` spawns a specialist agent with ONLY that MCP server's tools.
|
|
130
|
+
- The specialist has ZERO context beyond the task description you write. Include everything: what to do, all details, full content, background context.
|
|
131
|
+
- Plan MCP calls like any other agent spawn — define inputs, expected outputs, and what happens with the result.
|
|
132
|
+
- Multiple MCP calls to different servers can run in parallel if they don't depend on each other.
|
|
133
|
+
|
|
134
|
+
### Preventing Cross-Agent Impact
|
|
135
|
+
- Never let two agents write to the same file. Split by file or by section with clear ownership.
|
|
136
|
+
- Never let an agent modify global state (env vars, configs, databases) without the plan explicitly calling for it.
|
|
137
|
+
- Use workspace directories (`data/workspaces/{id}/`) as artifact stores. Each agent writes to its own path within the workspace.
|
|
138
|
+
- After all agents finish, the parent synthesizes results. Agents never directly consume each other's output during execution.
|
|
139
|
+
|
|
140
|
+
Load `readFile("skills/orchestration.md")` for full multi-agent coordination patterns, error recovery, and structured return conventions.
|
|
141
|
+
|
|
142
|
+
## Tracking Complex Work
|
|
143
|
+
|
|
144
|
+
For multi-step work, use `projectTracker("createProject")` to persist the plan:
|
|
145
|
+
- Mark tasks `in_progress` before starting, `done` with notes when finished.
|
|
146
|
+
- If interrupted → `projectTracker("listProjects")` to find and resume.
|
|
147
|
+
- Workspace files survive crashes — work is never lost.
|
|
148
|
+
|
|
149
|
+
## Re-Assessment
|
|
150
|
+
|
|
151
|
+
If you're 3+ steps into execution and:
|
|
152
|
+
- The approach isn't working as expected
|
|
153
|
+
- You discovered something that changes the requirements
|
|
154
|
+
- The scope is larger than initially estimated
|
|
155
|
+
|
|
156
|
+
**Stop. Re-read the original request. Re-plan from current state.** Don't push through a broken plan. If the new plan differs significantly, confirm with the user again.
|
|
157
|
+
|
|
158
|
+
## Planning Checklist
|
|
159
|
+
|
|
160
|
+
Before executing, verify:
|
|
161
|
+
- [ ] Gathered enough context (files, web, memory, conversation)
|
|
162
|
+
- [ ] Identified the best approach from available options
|
|
163
|
+
- [ ] Steps are ordered (dependencies resolved)
|
|
164
|
+
- [ ] Each step has a clear, verifiable outcome
|
|
165
|
+
- [ ] User has confirmed the plan (for complex work)
|
|
166
|
+
- [ ] Edge cases and potential failures considered
|
|
167
|
+
- [ ] Multi-agent tasks: contracts defined, boundaries set, no shared-file conflicts
|
|
168
|
+
- [ ] MCP tasks: task descriptions are self-contained, expected outputs specified
|
|
@@ -52,6 +52,7 @@ export async function buildSystemPrompt(taskInput, promptMode = "full", runtimeM
|
|
|
52
52
|
renderMCPTools(),
|
|
53
53
|
renderToolUsageRules(),
|
|
54
54
|
renderSkills(taskInput, 10),
|
|
55
|
+
renderMemory(),
|
|
55
56
|
renderSubagentContext(runtimeMeta.taskDescription || taskInput),
|
|
56
57
|
])
|
|
57
58
|
: await Promise.all([
|
|
@@ -65,7 +66,6 @@ export async function buildSystemPrompt(taskInput, promptMode = "full", runtimeM
|
|
|
65
66
|
renderMemory(),
|
|
66
67
|
renderSemanticRecall(taskInput),
|
|
67
68
|
renderDailyLog(),
|
|
68
|
-
renderOperationalGuidelines(),
|
|
69
69
|
]);
|
|
70
70
|
|
|
71
71
|
const runtime = renderRuntime(runtimeMeta);
|
|
@@ -162,7 +162,7 @@ You MUST respond with a JSON object matching this exact schema on every turn:
|
|
|
162
162
|
- Task complete and verified → concise outcome in 1-3 sentences. finalResponse = true.
|
|
163
163
|
|
|
164
164
|
## Task execution rules
|
|
165
|
-
1.
|
|
165
|
+
1. **Decide: plan or just do it.** Simple task (single action, clear instructions, quick fix) → start immediately with a tool call. Complex task (3+ steps, multiple approaches, unclear scope, high stakes, multi-agent, new feature, multi-file changes) → load the planning skill first (\`readFile("skills/planning.md")\`), gather context, break into steps, **present the plan to the user and get confirmation before executing**. When in doubt → plan. The cost of planning is low; the cost of rework is high.
|
|
166
166
|
2. Chain multiple tool calls. After each result: need more? Call another. Done? Verify first, then finalize.
|
|
167
167
|
3. After writing/editing any file, read it back to verify.
|
|
168
168
|
4. After code changes, run build/tests. Fix failures until clean.
|
|
@@ -170,6 +170,7 @@ You MUST respond with a JSON object matching this exact schema on every turn:
|
|
|
170
170
|
6. Never give up. Never ask the user to do it manually. Never report a problem without attempting to solve it.
|
|
171
171
|
7. Never claim you did something without actually calling the tool.
|
|
172
172
|
8. Never set finalResponse=true while errors or failures exist.
|
|
173
|
+
9. If 3+ steps into execution and something doesn't add up → stop, re-read the request, re-plan from current state.
|
|
173
174
|
|
|
174
175
|
## Understanding user intent
|
|
175
176
|
- Read the full request carefully. Identify exactly what the user wants done.
|
|
@@ -181,7 +182,15 @@ You MUST respond with a JSON object matching this exact schema on every turn:
|
|
|
181
182
|
- 1-3 sentences. What happened, from the user's perspective.
|
|
182
183
|
- Never dump tool output, full email bodies, API responses, status codes, message IDs, or JSON.
|
|
183
184
|
- Never ask what to do next or offer follow-up options.
|
|
184
|
-
- Never expose internal details (tool names, IDs, technical artifacts)
|
|
185
|
+
- Never expose internal details (tool names, IDs, technical artifacts).
|
|
186
|
+
|
|
187
|
+
## Output efficiency
|
|
188
|
+
These rules apply to text responses sent to the user — NOT to tool params, sub-agent instructions, or task descriptions (those must remain detailed and complete).
|
|
189
|
+
- Go straight to the point. Try the simplest approach first.
|
|
190
|
+
- Lead with the answer or action, not the reasoning.
|
|
191
|
+
- Skip filler words, preamble, and unnecessary transitions.
|
|
192
|
+
- If you can say it in one sentence, don't use three.
|
|
193
|
+
- Focus text on: decisions needing input, status updates at milestones, errors that change the plan.`;
|
|
185
194
|
}
|
|
186
195
|
|
|
187
196
|
function renderToolDocs() {
|
|
@@ -197,12 +206,19 @@ ${unconfigured.map(t => `- ${t} — needs: ${TOOL_REQUIRED_KEYS[t].join(" or ")}
|
|
|
197
206
|
return `# Available Tools
|
|
198
207
|
|
|
199
208
|
All tool params are STRINGS. Pass them as an array of strings.
|
|
209
|
+
Use existing conversation context first — if you already have the data from a previous tool call, web search, file read, or user message, work with that. Only call a tool again when you need fresh or missing information.
|
|
200
210
|
|
|
201
211
|
## File Operations
|
|
202
212
|
Always use absolute paths. Resolve ~ and relative paths from the user's context before calling any file tool.
|
|
203
|
-
-
|
|
213
|
+
- MUST read a file before modifying it. Never edit blind — this will error if you haven't read the file first.
|
|
214
|
+
- Don't re-read files already in context. Use existing content — only re-read if you need fresh state after an edit.
|
|
215
|
+
- Read only what you need: use offset/limit to target specific sections, not the entire file.
|
|
216
|
+
- Prefer editFile for modifying existing files — it only sends the diff. Most edits should use this.
|
|
217
|
+
- applyPatch for multi-hunk changes — better than multiple editFile calls.
|
|
218
|
+
- writeFile only for creating new files or complete rewrites. Never writeFile to change a few lines.
|
|
219
|
+
- readFile(filePath, offset?, limit?) — Read file with line numbers. Use offset/limit to read specific sections.
|
|
204
220
|
- writeFile(filePath, content) — Create or overwrite file. Content is the complete file.
|
|
205
|
-
- editFile(filePath, oldString, newString) — Find-and-replace (exactly 3 params).
|
|
221
|
+
- editFile(filePath, oldString, newString) — Find-and-replace (exactly 3 params). Supports flexible whitespace matching.
|
|
206
222
|
- applyPatch(filePath, patch) — Apply unified diff patch. Better than editFile for multi-hunk changes.
|
|
207
223
|
- listDirectory(dirPath) — List files and folders with types and sizes.
|
|
208
224
|
- searchFiles(pattern, directory?, optionsJson?) — Find files by name pattern. opts: {"sortBy":"modified","maxDepth":3}
|
|
@@ -245,6 +261,7 @@ ${_isToolConfigured("textToSpeech") ? `- textToSpeech(text, optionsJson?) — Te
|
|
|
245
261
|
- sendFile(channel, target, filePath, caption?) — Send file to a DIFFERENT user on a specific channel.
|
|
246
262
|
|
|
247
263
|
## Memory
|
|
264
|
+
Persistent memory per tenant. Contents survive across conversations. Consult memory to build on previous experience.
|
|
248
265
|
- readMemory() — Read long-term MEMORY.md.
|
|
249
266
|
- writeMemory(entry, category?) — Add timestamped entry. category: "user-prefs", "project", "learned", etc.
|
|
250
267
|
- searchMemory(query, optionsJson?) — Search MEMORY.md and daily logs. opts: {"category":"...","limit":50}
|
|
@@ -253,6 +270,24 @@ ${_isToolConfigured("textToSpeech") ? `- textToSpeech(text, optionsJson?) — Te
|
|
|
253
270
|
- readDailyLog(date?) — Read daily log for date (YYYY-MM-DD). Omit for today.
|
|
254
271
|
- writeDailyLog(entry) — Append to today's daily log.
|
|
255
272
|
|
|
273
|
+
### What to save
|
|
274
|
+
- User preferences for workflow, tools, and communication style.
|
|
275
|
+
- Key architectural decisions, important file paths, and project structure.
|
|
276
|
+
- Solutions to recurring problems and debugging insights.
|
|
277
|
+
- When the user asks to remember something across sessions, save it immediately.
|
|
278
|
+
|
|
279
|
+
### What NOT to save
|
|
280
|
+
- Session-specific context (current task details, in-progress work, temporary state).
|
|
281
|
+
- Speculative or unverified conclusions from a single interaction.
|
|
282
|
+
- Information that duplicates what's already in memory — check first, update existing entries.
|
|
283
|
+
|
|
284
|
+
### When to use memory
|
|
285
|
+
- Start of a new conversation → readMemory() to recall user preferences and context.
|
|
286
|
+
- User gives a preference or rule → writeMemory() immediately, don't wait.
|
|
287
|
+
- User asks to forget something → find and remove the relevant entry.
|
|
288
|
+
- Learned something stable across multiple interactions → save it.
|
|
289
|
+
- Daily log for task tracking → writeDailyLog() at end of significant work.
|
|
290
|
+
|
|
256
291
|
## Agents
|
|
257
292
|
For complex multi-agent tasks, load \`readFile("skills/orchestration.md")\` first — covers parallel execution, contract-based planning, workspace artifacts, and coordination patterns.
|
|
258
293
|
- spawnAgent(taskDescription, optionsJson?) — Spawn sub-agent. opts: {"profile":"coder|researcher|writer|analyst","extraTools":[...],"skills":["skills/coding.md"],"parentContext":"...","model":"..."}. Pass skills array with skill paths from the Available Skills list — the skill content is injected directly into the sub-agent so it can follow the instructions without loading them. Task description must be comprehensive — sub-agent has no other context.
|
|
@@ -304,33 +339,42 @@ ${serverList}
|
|
|
304
339
|
function renderToolUsageRules() {
|
|
305
340
|
return `# Tool Usage Rules
|
|
306
341
|
|
|
307
|
-
##
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
342
|
+
## Workflow
|
|
343
|
+
1. Read → understand before touching anything.
|
|
344
|
+
2. Act → editFile for small changes, writeFile for rewrites. Use tools, never tell the user to do it manually.
|
|
345
|
+
3. Verify → readFile after writes. Run build/tests after code changes.
|
|
346
|
+
4. Fix → build/test fails → fix and re-verify until clean.
|
|
347
|
+
5. Report → 1-3 sentences. What happened, key outcomes. No raw output, no internal details.
|
|
348
|
+
|
|
349
|
+
## Tool Selection
|
|
350
|
+
- Small change → editFile. Full rewrite → writeFile. editFile keeps failing → switch to writeFile.
|
|
351
|
+
- Find content → searchContent/grep. Find files → searchFiles/glob/listDirectory.
|
|
352
|
+
- editFile oldString not found → re-read file, retry with exact content.
|
|
314
353
|
|
|
315
354
|
## Error Recovery
|
|
316
|
-
-
|
|
317
|
-
-
|
|
318
|
-
-
|
|
319
|
-
|
|
320
|
-
##
|
|
321
|
-
-
|
|
322
|
-
-
|
|
323
|
-
- No
|
|
324
|
-
- No error handling for impossible scenarios.
|
|
325
|
-
- Unused code → delete
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
-
|
|
333
|
-
-
|
|
355
|
+
- Tool fails → read error, try different approach. Fails again → try another. Exhaust options before reporting failure.
|
|
356
|
+
- Same params fail twice → stop and diagnose. Don't brute force.
|
|
357
|
+
- Never use destructive workarounds to clear a blocker.
|
|
358
|
+
|
|
359
|
+
## Code Quality
|
|
360
|
+
- Read before edit. Always. Use enough context in oldString for unambiguous match.
|
|
361
|
+
- Follow existing conventions. Match project patterns. Simplest correct solution wins.
|
|
362
|
+
- Only change what's requested. No extra features, refactoring, or "improvements" beyond scope.
|
|
363
|
+
- No comments/docstrings on untouched code. No error handling for impossible scenarios.
|
|
364
|
+
- Unused code → delete completely. No backwards-compatibility hacks.
|
|
365
|
+
- No command injection, XSS, SQL injection, path traversal. Never hardcode secrets.
|
|
366
|
+
|
|
367
|
+
## What NOT To Do
|
|
368
|
+
- NEVER expose raw API responses, status codes, message IDs, or internal artifacts.
|
|
369
|
+
- NEVER ask what to do next or offer follow-up options. Either do it or don't.
|
|
370
|
+
- NEVER claim "fixed" without calling writeFile/editFile. NEVER plan without executing.
|
|
371
|
+
- NEVER ask user to do things manually. NEVER give up after one failure.
|
|
372
|
+
- NEVER set finalResponse true without verification or while errors exist.
|
|
373
|
+
|
|
374
|
+
## Context Management
|
|
375
|
+
- \`<conversation-summary>\` blocks are compacted history — treat as ground truth for earlier work.
|
|
376
|
+
- Don't re-do work mentioned in the summary. Continue from where it left off.
|
|
377
|
+
- If context is growing long, write key decisions to memory before they get compacted.`;
|
|
334
378
|
}
|
|
335
379
|
|
|
336
380
|
async function renderSkills(taskInput, limit = 20) {
|
|
@@ -350,6 +394,7 @@ async function renderSkills(taskInput, limit = 20) {
|
|
|
350
394
|
return `# Available Skills
|
|
351
395
|
|
|
352
396
|
Before replying, scan this list. If a skill applies, use readFile to load it, then follow it.
|
|
397
|
+
Skills that need API keys or credentials access them from the runtime environment automatically — never ask the user for keys in chat.
|
|
353
398
|
|
|
354
399
|
${lines.join("\n")}${dirHint}`;
|
|
355
400
|
}
|
|
@@ -376,33 +421,7 @@ function renderDailyLog() {
|
|
|
376
421
|
return `# Today's Log (${today})\n\n${dailyLog}`;
|
|
377
422
|
}
|
|
378
423
|
|
|
379
|
-
|
|
380
|
-
return `# Operational Guidelines
|
|
381
|
-
|
|
382
|
-
## Workflow
|
|
383
|
-
1. Read every file before touching it.
|
|
384
|
-
2. Act with tools — editFile for small changes, writeFile for rewrites.
|
|
385
|
-
3. Verify — readFile after writes. Run build/tests after code changes.
|
|
386
|
-
4. Fix — if build/test fails, fix and re-verify until clean.
|
|
387
|
-
5. Report — brief result in 1-3 sentences. Never expose internal details (tool names, IDs, JSON, raw API data).
|
|
388
|
-
- NEVER set finalResponse true while a build error or test failure exists.
|
|
389
|
-
|
|
390
|
-
## Requirements
|
|
391
|
-
- Infer implied intent from vague requests. Ask only when truly ambiguous.
|
|
392
|
-
- Match existing code style and conventions.
|
|
393
|
-
|
|
394
|
-
## When Blocked
|
|
395
|
-
- Read the error, try a different approach. Don't brute force.
|
|
396
|
-
- Tool fails twice with same params → stop and diagnose.
|
|
397
|
-
- Never use destructive workarounds to clear a blocker.
|
|
398
|
-
|
|
399
|
-
## What NOT To Do
|
|
400
|
-
- NEVER expose raw API responses, status codes, message IDs, or internal artifacts to the user.
|
|
401
|
-
- NEVER ask the user what to do next or offer follow-up options. Either do it or don't.
|
|
402
|
-
- NEVER claim "fixed" without calling writeFile/editFile. NEVER plan without executing.
|
|
403
|
-
- NEVER ask user to do things manually. NEVER give up after one failure.
|
|
404
|
-
- NEVER set finalResponse true without verification. NEVER over-engineer.`;
|
|
405
|
-
}
|
|
424
|
+
// renderOperationalGuidelines merged into renderToolUsageRules
|
|
406
425
|
|
|
407
426
|
function renderSubagentContext(taskDescription) {
|
|
408
427
|
if (!taskDescription) return null;
|
|
@@ -423,7 +442,10 @@ function renderRuntime(meta = {}) {
|
|
|
423
442
|
if (meta.model) parts.push(`model=${meta.model}`);
|
|
424
443
|
if (meta.thinkingLevel) parts.push(`thinking=${meta.thinkingLevel}`);
|
|
425
444
|
if (meta.agentId) parts.push(`agent=${meta.agentId}`);
|
|
426
|
-
|
|
445
|
+
parts.push(`date=${new Date().toISOString().split("T")[0]}`);
|
|
446
|
+
parts.push(`os=${process.platform}/${process.arch}`);
|
|
447
|
+
parts.push(`cwd=${process.cwd()}`);
|
|
448
|
+
parts.push(`shell=${process.env.SHELL || "unknown"}`);
|
|
427
449
|
return `Runtime: ${parts.join(" | ")}`;
|
|
428
450
|
}
|
|
429
451
|
|
package/src/cli.js
CHANGED
|
@@ -871,10 +871,18 @@ function handleSandbox(action, args) {
|
|
|
871
871
|
console.error(`\n ${S.cross} Usage: daemora sandbox add ${t.dim("<absolute-path>")}\n`);
|
|
872
872
|
process.exit(1);
|
|
873
873
|
}
|
|
874
|
-
if (!newPath.startsWith("/") && !newPath.match(/^[A-Za-z]
|
|
874
|
+
if (!newPath.startsWith("/") && !newPath.match(/^[A-Za-z]:[\\\/]/)) {
|
|
875
875
|
console.error(`\n ${S.cross} Path must be absolute (start with / or C:\\)\n`);
|
|
876
876
|
process.exit(1);
|
|
877
877
|
}
|
|
878
|
+
if (/[\x00-\x1f]/.test(newPath) || newPath.includes("\0")) {
|
|
879
|
+
console.error(`\n ${S.cross} Path must not contain control characters or null bytes.\n`);
|
|
880
|
+
process.exit(1);
|
|
881
|
+
}
|
|
882
|
+
if (/(^|[\\/])\.\.([\\/]|$)/.test(newPath)) {
|
|
883
|
+
console.error(`\n ${S.cross} Path must not contain ".." traversal.\n`);
|
|
884
|
+
process.exit(1);
|
|
885
|
+
}
|
|
878
886
|
const updated = [...new Set([...allowedPaths, newPath])];
|
|
879
887
|
writeEnvKey("ALLOWED_PATHS", updated.join(","));
|
|
880
888
|
console.log(`\n${header} ${S.check} ${t.bold(newPath)} added to allowed paths.`);
|
|
@@ -909,6 +917,10 @@ function handleSandbox(action, args) {
|
|
|
909
917
|
console.error(`\n ${S.cross} Usage: daemora sandbox block ${t.dim("<absolute-path>")}\n`);
|
|
910
918
|
process.exit(1);
|
|
911
919
|
}
|
|
920
|
+
if (/[\x00-\x1f]/.test(blockPath) || /(^|[\\/])\.\.([\\/]|$)/.test(blockPath)) {
|
|
921
|
+
console.error(`\n ${S.cross} Invalid path — no control characters or ".." traversal allowed.\n`);
|
|
922
|
+
process.exit(1);
|
|
923
|
+
}
|
|
912
924
|
const updated = [...new Set([...blockedPaths, blockPath])];
|
|
913
925
|
writeEnvKey("BLOCKED_PATHS", updated.join(","));
|
|
914
926
|
console.log(`\n${header} ${S.check} ${t.bold(blockPath)} added to blocked paths.\n`);
|
|
@@ -972,15 +984,24 @@ async function handleTenant(action, args) {
|
|
|
972
984
|
const port = process.env.PORT || "8081";
|
|
973
985
|
const base = `http://localhost:${port}`;
|
|
974
986
|
|
|
987
|
+
// Read auth token for API calls
|
|
988
|
+
const tokenPath = join(config.dataDir, "auth-token");
|
|
989
|
+
const authToken = existsSync(tokenPath) ? readFileSync(tokenPath, "utf-8").trim() : "";
|
|
990
|
+
|
|
975
991
|
async function apiCall(method, path, body) {
|
|
976
992
|
const { default: http } = await import("http");
|
|
993
|
+
// Ensure path starts with /api/
|
|
994
|
+
const apiPath = path.startsWith("/api/") ? path : `/api${path}`;
|
|
977
995
|
return new Promise((resolve, reject) => {
|
|
978
996
|
const opts = {
|
|
979
997
|
hostname: "localhost",
|
|
980
998
|
port: parseInt(port),
|
|
981
|
-
path,
|
|
999
|
+
path: apiPath,
|
|
982
1000
|
method,
|
|
983
|
-
headers: {
|
|
1001
|
+
headers: {
|
|
1002
|
+
"Content-Type": "application/json",
|
|
1003
|
+
...(authToken ? { "Authorization": `Bearer ${authToken}` } : {}),
|
|
1004
|
+
},
|
|
984
1005
|
};
|
|
985
1006
|
const req = http.request(opts, (res) => {
|
|
986
1007
|
let data = "";
|
|
@@ -1285,9 +1306,100 @@ async function handleTenant(action, args) {
|
|
|
1285
1306
|
break;
|
|
1286
1307
|
}
|
|
1287
1308
|
|
|
1309
|
+
case "workspace": {
|
|
1310
|
+
// daemora tenant workspace <tenantId> — show paths
|
|
1311
|
+
// daemora tenant workspace <tenantId> add <path> — add to allowedPaths
|
|
1312
|
+
// daemora tenant workspace <tenantId> remove <path> — remove from allowedPaths
|
|
1313
|
+
// daemora tenant workspace <tenantId> block <path> — add to blockedPaths
|
|
1314
|
+
// daemora tenant workspace <tenantId> unblock <path> — remove from blockedPaths
|
|
1315
|
+
const [tenantId, wsAction, wsPath] = args;
|
|
1316
|
+
if (!tenantId) {
|
|
1317
|
+
console.error(`\n ${S.cross} Usage: daemora tenant workspace ${t.dim("<tenantId> [add|remove|block|unblock] [path]")}\n`);
|
|
1318
|
+
process.exit(1);
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
const { default: tm } = await import("./tenants/TenantManager.js");
|
|
1322
|
+
const tenant = tm.get(tenantId);
|
|
1323
|
+
if (!tenant) {
|
|
1324
|
+
console.error(`\n ${S.cross} Tenant "${tenantId}" not found.\n`);
|
|
1325
|
+
process.exit(1);
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
if (!wsAction) {
|
|
1329
|
+
// Show current workspace paths
|
|
1330
|
+
console.log(header);
|
|
1331
|
+
console.log(` ${S.bar} Tenant ${t.bold(tenantId)}`);
|
|
1332
|
+
console.log(` ${S.bar} Workspace ${t.dim(tm.getWorkspace(tenantId))}`);
|
|
1333
|
+
const allowed = tenant.allowedPaths || [];
|
|
1334
|
+
const blocked = tenant.blockedPaths || [];
|
|
1335
|
+
if (allowed.length > 0) {
|
|
1336
|
+
console.log(` ${S.bar} Allowed paths:`);
|
|
1337
|
+
for (const p of allowed) console.log(` ${S.bar} ${S.check} ${p}`);
|
|
1338
|
+
} else {
|
|
1339
|
+
console.log(` ${S.bar} Allowed paths ${t.muted("(none — uses global or workspace default)")}`);
|
|
1340
|
+
}
|
|
1341
|
+
if (blocked.length > 0) {
|
|
1342
|
+
console.log(` ${S.bar} Blocked paths:`);
|
|
1343
|
+
for (const p of blocked) console.log(` ${S.bar} ${S.cross} ${p}`);
|
|
1344
|
+
} else {
|
|
1345
|
+
console.log(` ${S.bar} Blocked paths ${t.muted("(none)")}`);
|
|
1346
|
+
}
|
|
1347
|
+
console.log("");
|
|
1348
|
+
break;
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
// Validate path is absolute
|
|
1352
|
+
if (["add", "remove", "block", "unblock"].includes(wsAction)) {
|
|
1353
|
+
if (!wsPath) {
|
|
1354
|
+
console.error(`\n ${S.cross} Usage: daemora tenant workspace ${tenantId} ${wsAction} ${t.dim("<absolute-path>")}\n`);
|
|
1355
|
+
process.exit(1);
|
|
1356
|
+
}
|
|
1357
|
+
if (!wsPath.startsWith("/") && !/^[A-Za-z]:\\/.test(wsPath)) {
|
|
1358
|
+
console.error(`\n ${S.cross} Path must be absolute (start with / or C:\\)\n`);
|
|
1359
|
+
process.exit(1);
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
try {
|
|
1364
|
+
if (wsAction === "add") {
|
|
1365
|
+
const updated = [...new Set([...(tenant.allowedPaths || []), wsPath])];
|
|
1366
|
+
tm.set(tenantId, { allowedPaths: updated });
|
|
1367
|
+
console.log(`\n${header} ${S.check} ${t.bold(wsPath)} added to allowedPaths for ${t.bold(tenantId)}\n`);
|
|
1368
|
+
} else if (wsAction === "remove") {
|
|
1369
|
+
const updated = (tenant.allowedPaths || []).filter(p => p !== wsPath);
|
|
1370
|
+
if (updated.length === (tenant.allowedPaths || []).length) {
|
|
1371
|
+
console.error(`\n ${S.cross} "${wsPath}" not found in allowedPaths.\n`);
|
|
1372
|
+
process.exit(1);
|
|
1373
|
+
}
|
|
1374
|
+
tm.set(tenantId, { allowedPaths: updated });
|
|
1375
|
+
console.log(`\n${header} ${S.check} ${t.bold(wsPath)} removed from allowedPaths for ${t.bold(tenantId)}\n`);
|
|
1376
|
+
} else if (wsAction === "block") {
|
|
1377
|
+
const updated = [...new Set([...(tenant.blockedPaths || []), wsPath])];
|
|
1378
|
+
tm.set(tenantId, { blockedPaths: updated });
|
|
1379
|
+
console.log(`\n${header} ${S.check} ${t.bold(wsPath)} added to blockedPaths for ${t.bold(tenantId)}\n`);
|
|
1380
|
+
} else if (wsAction === "unblock") {
|
|
1381
|
+
const updated = (tenant.blockedPaths || []).filter(p => p !== wsPath);
|
|
1382
|
+
if (updated.length === (tenant.blockedPaths || []).length) {
|
|
1383
|
+
console.error(`\n ${S.cross} "${wsPath}" not found in blockedPaths.\n`);
|
|
1384
|
+
process.exit(1);
|
|
1385
|
+
}
|
|
1386
|
+
tm.set(tenantId, { blockedPaths: updated });
|
|
1387
|
+
console.log(`\n${header} ${S.check} ${t.bold(wsPath)} removed from blockedPaths for ${t.bold(tenantId)}\n`);
|
|
1388
|
+
} else {
|
|
1389
|
+
console.error(`\n ${S.cross} Unknown workspace action: ${wsAction}`);
|
|
1390
|
+
console.log(` ${t.muted("Usage:")} daemora tenant workspace ${t.dim("<id> [add|remove|block|unblock] <path>")}\n`);
|
|
1391
|
+
process.exit(1);
|
|
1392
|
+
}
|
|
1393
|
+
} catch (err) {
|
|
1394
|
+
console.error(`\n ${S.cross} ${err.message}\n`);
|
|
1395
|
+
process.exit(1);
|
|
1396
|
+
}
|
|
1397
|
+
break;
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1288
1400
|
default:
|
|
1289
1401
|
console.error(`\n ${S.cross} Unknown tenant command: ${action || "(none)"}`);
|
|
1290
|
-
console.log(` ${t.muted("Usage:")} daemora tenant ${t.dim("[list|show|set|plan|suspend|unsuspend|reset|delete|apikey|channel]")}\n`);
|
|
1402
|
+
console.log(` ${t.muted("Usage:")} daemora tenant ${t.dim("[list|show|set|plan|suspend|unsuspend|reset|delete|apikey|channel|workspace]")}\n`);
|
|
1291
1403
|
process.exit(1);
|
|
1292
1404
|
}
|
|
1293
1405
|
}
|
|
@@ -2193,6 +2305,11 @@ ${line}
|
|
|
2193
2305
|
${t.cmd("tenant channel unset")} ${t.dim("<id> <key>")} Remove a channel credential
|
|
2194
2306
|
${t.cmd("tenant channel list")} ${t.dim("<id>")} List stored channel credential keys
|
|
2195
2307
|
${t.muted(" channel keys: email email_password resend_api_key resend_from")}
|
|
2308
|
+
${t.cmd("tenant workspace")} ${t.dim("<id>")} Show workspace + allowed/blocked paths
|
|
2309
|
+
${t.cmd("tenant workspace")} ${t.dim("<id> add <path>")} Add path to tenant's allowedPaths
|
|
2310
|
+
${t.cmd("tenant workspace")} ${t.dim("<id> remove <path>")} Remove from allowedPaths
|
|
2311
|
+
${t.cmd("tenant workspace")} ${t.dim("<id> block <path>")} Add to blockedPaths
|
|
2312
|
+
${t.cmd("tenant workspace")} ${t.dim("<id> unblock <path>")} Remove from blockedPaths
|
|
2196
2313
|
|
|
2197
2314
|
${t.cmd("channels")} List all 19 supported channels + setup status
|
|
2198
2315
|
${t.cmd("models")} List all model providers + task-type routing
|
|
@@ -2247,6 +2364,9 @@ ${line}
|
|
|
2247
2364
|
${t.dim("$")} daemora tenant channel set telegram:123 email_password xxxx-xxxx-xxxx-xxxx
|
|
2248
2365
|
${t.dim("$")} daemora tenant channel list telegram:123
|
|
2249
2366
|
${t.dim("$")} daemora tenant channel unset telegram:123 email_password
|
|
2367
|
+
${t.dim("$")} daemora tenant workspace telegram:123
|
|
2368
|
+
${t.dim("$")} daemora tenant workspace telegram:123 add /home/user/projects
|
|
2369
|
+
${t.dim("$")} daemora tenant workspace telegram:123 block /home/user/private
|
|
2250
2370
|
${t.dim("$")} daemora doctor
|
|
2251
2371
|
`);
|
|
2252
2372
|
}
|