@agent-workspace/mcp-server 0.2.1 → 0.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 +42 -5
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -568
- package/dist/index.js.map +1 -1
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +726 -0
- package/dist/index.test.js.map +1 -0
- package/dist/tools/artifact.d.ts +6 -0
- package/dist/tools/artifact.d.ts.map +1 -0
- package/dist/tools/artifact.js +428 -0
- package/dist/tools/artifact.js.map +1 -0
- package/dist/tools/config.d.ts +6 -0
- package/dist/tools/config.d.ts.map +1 -0
- package/dist/tools/config.js +91 -0
- package/dist/tools/config.js.map +1 -0
- package/dist/tools/contract.d.ts +6 -0
- package/dist/tools/contract.d.ts.map +1 -0
- package/dist/tools/contract.js +233 -0
- package/dist/tools/contract.js.map +1 -0
- package/dist/tools/identity.d.ts +6 -0
- package/dist/tools/identity.d.ts.map +1 -0
- package/dist/tools/identity.js +91 -0
- package/dist/tools/identity.js.map +1 -0
- package/dist/tools/memory.d.ts +6 -0
- package/dist/tools/memory.d.ts.map +1 -0
- package/dist/tools/memory.js +145 -0
- package/dist/tools/memory.js.map +1 -0
- package/dist/tools/project.d.ts +6 -0
- package/dist/tools/project.d.ts.map +1 -0
- package/dist/tools/project.js +184 -0
- package/dist/tools/project.js.map +1 -0
- package/dist/tools/reputation.d.ts +6 -0
- package/dist/tools/reputation.d.ts.map +1 -0
- package/dist/tools/reputation.js +206 -0
- package/dist/tools/reputation.js.map +1 -0
- package/dist/tools/status.d.ts +6 -0
- package/dist/tools/status.d.ts.map +1 -0
- package/dist/tools/status.js +223 -0
- package/dist/tools/status.js.map +1 -0
- package/dist/tools/swarm.d.ts +6 -0
- package/dist/tools/swarm.d.ts.map +1 -0
- package/dist/tools/swarm.js +483 -0
- package/dist/tools/swarm.js.map +1 -0
- package/dist/tools/task.d.ts +6 -0
- package/dist/tools/task.d.ts.map +1 -0
- package/dist/tools/task.js +347 -0
- package/dist/tools/task.js.map +1 -0
- package/dist/utils.d.ts +23 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +56 -0
- package/dist/utils.js.map +1 -0
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -28,28 +28,65 @@ It will auto-discover the AWP workspace from the current directory (or use `AWP_
|
|
|
28
28
|
|
|
29
29
|
## Tools
|
|
30
30
|
|
|
31
|
+
### Core Identity & Context
|
|
32
|
+
|
|
31
33
|
| Tool | Description |
|
|
32
34
|
|------|-------------|
|
|
33
35
|
| `awp_read_identity` | Read agent identity (name, capabilities, DID) |
|
|
34
36
|
| `awp_read_soul` | Read behavioral constraints (values, boundaries, governance) |
|
|
35
37
|
| `awp_read_user` | Read human profile |
|
|
36
|
-
| `
|
|
37
|
-
| `
|
|
38
|
+
| `awp_read_agents` | Read operations config (AGENTS.md) |
|
|
39
|
+
| `awp_read_tools` | Read tools config (TOOLS.md) |
|
|
40
|
+
| `awp_read_heartbeat` | Read heartbeat config (HEARTBEAT.md) |
|
|
41
|
+
|
|
42
|
+
### Memory Operations
|
|
43
|
+
|
|
44
|
+
| Tool | Description |
|
|
45
|
+
|------|-------------|
|
|
46
|
+
| `awp_read_memory` | Read memory (daily, longterm, or recent logs) |
|
|
47
|
+
| `awp_write_memory` | Log structured memory entries to daily log |
|
|
48
|
+
|
|
49
|
+
### Knowledge Artifacts (SMP)
|
|
50
|
+
|
|
51
|
+
| Tool | Description |
|
|
52
|
+
|------|-------------|
|
|
38
53
|
| `awp_artifact_read` | Read a knowledge artifact by slug |
|
|
39
|
-
| `awp_artifact_write` | Create or update a knowledge artifact |
|
|
54
|
+
| `awp_artifact_write` | Create or update a knowledge artifact with versioning |
|
|
40
55
|
| `awp_artifact_list` | List all artifacts (optional tag filter) |
|
|
41
56
|
| `awp_artifact_search` | Search artifacts by content, title, or tags |
|
|
42
|
-
|
|
57
|
+
|
|
58
|
+
### Reputation (RDP)
|
|
59
|
+
|
|
60
|
+
| Tool | Description |
|
|
61
|
+
|------|-------------|
|
|
62
|
+
| `awp_reputation_query` | Query reputation profiles with time-based decay applied |
|
|
63
|
+
| `awp_reputation_signal` | Log reputation signals (uses EWMA with decay) |
|
|
64
|
+
|
|
65
|
+
### Delegation Contracts (RDP)
|
|
66
|
+
|
|
67
|
+
| Tool | Description |
|
|
68
|
+
|------|-------------|
|
|
69
|
+
| `awp_contract_create` | Create delegation contracts between agents |
|
|
70
|
+
| `awp_contract_evaluate` | Evaluate contracts and generate reputation signals |
|
|
71
|
+
| `awp_contract_list` | List all contracts with optional status filter |
|
|
72
|
+
|
|
73
|
+
### Workspace Management
|
|
74
|
+
|
|
75
|
+
| Tool | Description |
|
|
76
|
+
|------|-------------|
|
|
77
|
+
| `awp_workspace_status` | Workspace health check (files present, stats) |
|
|
43
78
|
|
|
44
79
|
## How It Works
|
|
45
80
|
|
|
46
|
-
The MCP server reads and writes AWP workspace files directly — no database, no daemon. Your agent's identity, memory,
|
|
81
|
+
The MCP server reads and writes AWP workspace files directly — no database, no daemon. Your agent's identity, memory, knowledge artifacts, and reputation profiles are just Markdown files with YAML frontmatter, stored in a directory and compatible with Git.
|
|
47
82
|
|
|
48
83
|
When an AI agent connects via MCP, it can:
|
|
49
84
|
- **Read** its identity, soul, and user context at the start of each session
|
|
50
85
|
- **Write** memory entries as it works
|
|
51
86
|
- **Create and update** knowledge artifacts with full provenance tracking
|
|
52
87
|
- **Search** its accumulated knowledge
|
|
88
|
+
- **Query and update** reputation profiles for itself and other agents
|
|
89
|
+
- **Create and evaluate** delegation contracts for multi-agent coordination
|
|
53
90
|
|
|
54
91
|
## Part of AWP
|
|
55
92
|
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG"}
|
package/dist/index.js
CHANGED
|
@@ -1,578 +1,40 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* AWP MCP Server
|
|
4
|
+
*
|
|
5
|
+
* MCP server exposing Agent Workspace Protocol operations.
|
|
6
|
+
* Plug any AWP workspace into any MCP client.
|
|
7
|
+
*/
|
|
2
8
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
9
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
10
|
+
import { AWP_VERSION } from "@agent-workspace/core";
|
|
11
|
+
// Tool registration modules
|
|
12
|
+
import { registerIdentityTools } from "./tools/identity.js";
|
|
13
|
+
import { registerMemoryTools } from "./tools/memory.js";
|
|
14
|
+
import { registerArtifactTools } from "./tools/artifact.js";
|
|
15
|
+
import { registerStatusTools } from "./tools/status.js";
|
|
16
|
+
import { registerReputationTools } from "./tools/reputation.js";
|
|
17
|
+
import { registerContractTools } from "./tools/contract.js";
|
|
18
|
+
import { registerProjectTools } from "./tools/project.js";
|
|
19
|
+
import { registerTaskTools } from "./tools/task.js";
|
|
20
|
+
import { registerConfigTools } from "./tools/config.js";
|
|
21
|
+
import { registerSwarmTools } from "./tools/swarm.js";
|
|
22
|
+
// Create MCP server
|
|
9
23
|
const server = new McpServer({
|
|
10
24
|
name: "awp-workspace",
|
|
11
25
|
version: AWP_VERSION,
|
|
12
26
|
});
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
catch {
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Get agent DID from workspace manifest, or "anonymous"
|
|
30
|
-
*/
|
|
31
|
-
async function getAgentDid(root) {
|
|
32
|
-
try {
|
|
33
|
-
const raw = await readFile(join(root, ".awp", "workspace.json"), "utf-8");
|
|
34
|
-
const manifest = JSON.parse(raw);
|
|
35
|
-
return manifest.agent?.did || "anonymous";
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
return "anonymous";
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
// --- Tool: awp_read_identity ---
|
|
42
|
-
server.registerTool("awp_read_identity", {
|
|
43
|
-
title: "Read Agent Identity",
|
|
44
|
-
description: "Read this agent's identity (name, creature, capabilities, DID) from the AWP workspace",
|
|
45
|
-
inputSchema: {},
|
|
46
|
-
}, async () => {
|
|
47
|
-
const root = getWorkspaceRoot();
|
|
48
|
-
const path = join(root, "IDENTITY.md");
|
|
49
|
-
try {
|
|
50
|
-
const raw = await readFile(path, "utf-8");
|
|
51
|
-
const { data, content } = matter(raw);
|
|
52
|
-
return {
|
|
53
|
-
content: [
|
|
54
|
-
{
|
|
55
|
-
type: "text",
|
|
56
|
-
text: JSON.stringify({ frontmatter: data, body: content.trim() }, null, 2),
|
|
57
|
-
},
|
|
58
|
-
],
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
return {
|
|
63
|
-
content: [{ type: "text", text: "Error: IDENTITY.md not found" }],
|
|
64
|
-
isError: true,
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
// --- Tool: awp_read_soul ---
|
|
69
|
-
server.registerTool("awp_read_soul", {
|
|
70
|
-
title: "Read Agent Soul",
|
|
71
|
-
description: "Read this agent's values, boundaries, and governance rules from the AWP workspace",
|
|
72
|
-
inputSchema: {},
|
|
73
|
-
}, async () => {
|
|
74
|
-
const root = getWorkspaceRoot();
|
|
75
|
-
const path = join(root, "SOUL.md");
|
|
76
|
-
try {
|
|
77
|
-
const raw = await readFile(path, "utf-8");
|
|
78
|
-
const { data, content } = matter(raw);
|
|
79
|
-
return {
|
|
80
|
-
content: [
|
|
81
|
-
{
|
|
82
|
-
type: "text",
|
|
83
|
-
text: JSON.stringify({ frontmatter: data, body: content.trim() }, null, 2),
|
|
84
|
-
},
|
|
85
|
-
],
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
catch {
|
|
89
|
-
return {
|
|
90
|
-
content: [{ type: "text", text: "Error: SOUL.md not found" }],
|
|
91
|
-
isError: true,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
// --- Tool: awp_read_user ---
|
|
96
|
-
server.registerTool("awp_read_user", {
|
|
97
|
-
title: "Read Human Profile",
|
|
98
|
-
description: "Read the human user's profile from the AWP workspace",
|
|
99
|
-
inputSchema: {},
|
|
100
|
-
}, async () => {
|
|
101
|
-
const root = getWorkspaceRoot();
|
|
102
|
-
const path = join(root, "USER.md");
|
|
103
|
-
try {
|
|
104
|
-
const raw = await readFile(path, "utf-8");
|
|
105
|
-
const { data, content } = matter(raw);
|
|
106
|
-
return {
|
|
107
|
-
content: [
|
|
108
|
-
{
|
|
109
|
-
type: "text",
|
|
110
|
-
text: JSON.stringify({ frontmatter: data, body: content.trim() }, null, 2),
|
|
111
|
-
},
|
|
112
|
-
],
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
catch {
|
|
116
|
-
return {
|
|
117
|
-
content: [{ type: "text", text: "Error: USER.md not found" }],
|
|
118
|
-
isError: true,
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
// --- Tool: awp_read_memory ---
|
|
123
|
-
server.registerTool("awp_read_memory", {
|
|
124
|
-
title: "Read Memory",
|
|
125
|
-
description: "Read memory entries. Specify a date (YYYY-MM-DD) for daily logs, or 'longterm' for MEMORY.md, or 'recent' for the last 3 days",
|
|
126
|
-
inputSchema: {
|
|
127
|
-
target: z
|
|
128
|
-
.string()
|
|
129
|
-
.describe("Which memory to read: a date like '2026-01-30', 'longterm', or 'recent'"),
|
|
130
|
-
},
|
|
131
|
-
}, async ({ target }) => {
|
|
132
|
-
const root = getWorkspaceRoot();
|
|
133
|
-
if (target === "longterm") {
|
|
134
|
-
const path = join(root, "MEMORY.md");
|
|
135
|
-
try {
|
|
136
|
-
const raw = await readFile(path, "utf-8");
|
|
137
|
-
const { data, content } = matter(raw);
|
|
138
|
-
return {
|
|
139
|
-
content: [
|
|
140
|
-
{
|
|
141
|
-
type: "text",
|
|
142
|
-
text: JSON.stringify({ frontmatter: data, body: content.trim() }, null, 2),
|
|
143
|
-
},
|
|
144
|
-
],
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
catch {
|
|
148
|
-
return {
|
|
149
|
-
content: [
|
|
150
|
-
{ type: "text", text: "No long-term memory file exists yet." },
|
|
151
|
-
],
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
if (target === "recent") {
|
|
156
|
-
const memDir = join(root, MEMORY_DIR);
|
|
157
|
-
try {
|
|
158
|
-
const files = await readdir(memDir);
|
|
159
|
-
const mdFiles = files
|
|
160
|
-
.filter((f) => f.endsWith(".md"))
|
|
161
|
-
.sort()
|
|
162
|
-
.reverse()
|
|
163
|
-
.slice(0, 3);
|
|
164
|
-
const results = [];
|
|
165
|
-
for (const f of mdFiles) {
|
|
166
|
-
const raw = await readFile(join(memDir, f), "utf-8");
|
|
167
|
-
const { data, content } = matter(raw);
|
|
168
|
-
results.push(`--- ${f} ---\n${JSON.stringify(data, null, 2)}\n${content.trim()}`);
|
|
169
|
-
}
|
|
170
|
-
return {
|
|
171
|
-
content: [
|
|
172
|
-
{
|
|
173
|
-
type: "text",
|
|
174
|
-
text: results.length
|
|
175
|
-
? results.join("\n\n")
|
|
176
|
-
: "No recent memory entries.",
|
|
177
|
-
},
|
|
178
|
-
],
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
catch {
|
|
182
|
-
return {
|
|
183
|
-
content: [{ type: "text", text: "No memory directory found." }],
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
// Specific date
|
|
188
|
-
const path = join(root, MEMORY_DIR, `${target}.md`);
|
|
189
|
-
try {
|
|
190
|
-
const raw = await readFile(path, "utf-8");
|
|
191
|
-
const { data, content } = matter(raw);
|
|
192
|
-
return {
|
|
193
|
-
content: [
|
|
194
|
-
{
|
|
195
|
-
type: "text",
|
|
196
|
-
text: JSON.stringify({ frontmatter: data, body: content.trim() }, null, 2),
|
|
197
|
-
},
|
|
198
|
-
],
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
catch {
|
|
202
|
-
return {
|
|
203
|
-
content: [
|
|
204
|
-
{ type: "text", text: `No memory entry for ${target}.` },
|
|
205
|
-
],
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
// --- Tool: awp_write_memory ---
|
|
210
|
-
server.registerTool("awp_write_memory", {
|
|
211
|
-
title: "Write Memory",
|
|
212
|
-
description: "Append an entry to today's memory log in the AWP workspace",
|
|
213
|
-
inputSchema: {
|
|
214
|
-
content: z.string().describe("The memory entry to log"),
|
|
215
|
-
tags: z
|
|
216
|
-
.array(z.string())
|
|
217
|
-
.optional()
|
|
218
|
-
.describe("Optional categorization tags"),
|
|
219
|
-
},
|
|
220
|
-
}, async ({ content: entryContent, tags }) => {
|
|
221
|
-
const root = getWorkspaceRoot();
|
|
222
|
-
const memDir = join(root, MEMORY_DIR);
|
|
223
|
-
await mkdir(memDir, { recursive: true });
|
|
224
|
-
const date = new Date().toISOString().split("T")[0];
|
|
225
|
-
const time = new Date().toTimeString().slice(0, 5);
|
|
226
|
-
const filePath = join(memDir, `${date}.md`);
|
|
227
|
-
const entry = {
|
|
228
|
-
time,
|
|
229
|
-
content: entryContent,
|
|
230
|
-
tags: tags?.length ? tags : undefined,
|
|
231
|
-
};
|
|
232
|
-
let fileData;
|
|
233
|
-
try {
|
|
234
|
-
const raw = await readFile(filePath, "utf-8");
|
|
235
|
-
fileData = matter(raw);
|
|
236
|
-
if (!fileData.data.entries)
|
|
237
|
-
fileData.data.entries = [];
|
|
238
|
-
fileData.data.entries.push(entry);
|
|
239
|
-
}
|
|
240
|
-
catch {
|
|
241
|
-
fileData = {
|
|
242
|
-
data: {
|
|
243
|
-
awp: AWP_VERSION,
|
|
244
|
-
type: "memory-daily",
|
|
245
|
-
date,
|
|
246
|
-
entries: [entry],
|
|
247
|
-
},
|
|
248
|
-
content: `\n# ${date}\n\n`,
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
const tagStr = tags?.length ? ` [${tags.join(", ")}]` : "";
|
|
252
|
-
fileData.content += `- **${time}** — ${entryContent}${tagStr}\n`;
|
|
253
|
-
const output = matter.stringify(fileData.content, fileData.data);
|
|
254
|
-
await writeFile(filePath, output, "utf-8");
|
|
255
|
-
return {
|
|
256
|
-
content: [
|
|
257
|
-
{
|
|
258
|
-
type: "text",
|
|
259
|
-
text: `Logged to memory/${date}.md at ${time}`,
|
|
260
|
-
},
|
|
261
|
-
],
|
|
262
|
-
};
|
|
263
|
-
});
|
|
264
|
-
// --- Tool: awp_artifact_read ---
|
|
265
|
-
server.registerTool("awp_artifact_read", {
|
|
266
|
-
title: "Read Knowledge Artifact",
|
|
267
|
-
description: "Read a knowledge artifact by slug. Returns metadata (title, version, confidence, provenance) and body content.",
|
|
268
|
-
inputSchema: {
|
|
269
|
-
slug: z.string().describe("Artifact slug (e.g., 'llm-context-research')"),
|
|
270
|
-
},
|
|
271
|
-
}, async ({ slug }) => {
|
|
272
|
-
const root = getWorkspaceRoot();
|
|
273
|
-
const path = join(root, ARTIFACTS_DIR, `${slug}.md`);
|
|
274
|
-
try {
|
|
275
|
-
const raw = await readFile(path, "utf-8");
|
|
276
|
-
const { data, content } = matter(raw);
|
|
277
|
-
return {
|
|
278
|
-
content: [
|
|
279
|
-
{
|
|
280
|
-
type: "text",
|
|
281
|
-
text: JSON.stringify({ frontmatter: data, body: content.trim() }, null, 2),
|
|
282
|
-
},
|
|
283
|
-
],
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
catch {
|
|
287
|
-
return {
|
|
288
|
-
content: [
|
|
289
|
-
{ type: "text", text: `Artifact "${slug}" not found.` },
|
|
290
|
-
],
|
|
291
|
-
isError: true,
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
});
|
|
295
|
-
// --- Tool: awp_artifact_write ---
|
|
296
|
-
server.registerTool("awp_artifact_write", {
|
|
297
|
-
title: "Write Knowledge Artifact",
|
|
298
|
-
description: "Create or update a knowledge artifact. If the artifact exists, increments version and appends provenance. If new, creates it with version 1.",
|
|
299
|
-
inputSchema: {
|
|
300
|
-
slug: z.string().describe("Artifact slug (lowercase, hyphens only)"),
|
|
301
|
-
title: z.string().optional().describe("Title (required for new artifacts)"),
|
|
302
|
-
content: z.string().describe("Markdown body content"),
|
|
303
|
-
tags: z.array(z.string()).optional().describe("Categorization tags"),
|
|
304
|
-
confidence: z
|
|
305
|
-
.number()
|
|
306
|
-
.min(0)
|
|
307
|
-
.max(1)
|
|
308
|
-
.optional()
|
|
309
|
-
.describe("Confidence score (0.0-1.0)"),
|
|
310
|
-
message: z.string().optional().describe("Commit message for provenance"),
|
|
311
|
-
},
|
|
312
|
-
}, async ({ slug, title, content: bodyContent, tags, confidence, message }) => {
|
|
313
|
-
const root = getWorkspaceRoot();
|
|
314
|
-
const artifactsDir = join(root, ARTIFACTS_DIR);
|
|
315
|
-
await mkdir(artifactsDir, { recursive: true });
|
|
316
|
-
const filePath = join(artifactsDir, `${slug}.md`);
|
|
317
|
-
const did = await getAgentDid(root);
|
|
318
|
-
const now = new Date().toISOString();
|
|
319
|
-
let fileData;
|
|
320
|
-
let version;
|
|
321
|
-
let isNew = false;
|
|
322
|
-
try {
|
|
323
|
-
const raw = await readFile(filePath, "utf-8");
|
|
324
|
-
fileData = matter(raw);
|
|
325
|
-
// Update existing
|
|
326
|
-
fileData.data.version = (fileData.data.version || 1) + 1;
|
|
327
|
-
version = fileData.data.version;
|
|
328
|
-
fileData.data.lastModified = now;
|
|
329
|
-
fileData.data.modifiedBy = did;
|
|
330
|
-
fileData.content = `\n${bodyContent}\n`;
|
|
331
|
-
if (confidence !== undefined)
|
|
332
|
-
fileData.data.confidence = confidence;
|
|
333
|
-
if (tags)
|
|
334
|
-
fileData.data.tags = tags;
|
|
335
|
-
if (title)
|
|
336
|
-
fileData.data.title = title;
|
|
337
|
-
// Add author if new
|
|
338
|
-
if (!fileData.data.authors?.includes(did)) {
|
|
339
|
-
if (!fileData.data.authors)
|
|
340
|
-
fileData.data.authors = [];
|
|
341
|
-
fileData.data.authors.push(did);
|
|
342
|
-
}
|
|
343
|
-
// Append provenance
|
|
344
|
-
if (!fileData.data.provenance)
|
|
345
|
-
fileData.data.provenance = [];
|
|
346
|
-
fileData.data.provenance.push({
|
|
347
|
-
agent: did,
|
|
348
|
-
action: "updated",
|
|
349
|
-
timestamp: now,
|
|
350
|
-
message,
|
|
351
|
-
confidence,
|
|
352
|
-
});
|
|
353
|
-
}
|
|
354
|
-
catch {
|
|
355
|
-
// Create new
|
|
356
|
-
isNew = true;
|
|
357
|
-
version = 1;
|
|
358
|
-
const artifactTitle = title ||
|
|
359
|
-
slug
|
|
360
|
-
.split("-")
|
|
361
|
-
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
362
|
-
.join(" ");
|
|
363
|
-
fileData = {
|
|
364
|
-
data: {
|
|
365
|
-
awp: AWP_VERSION,
|
|
366
|
-
smp: SMP_VERSION,
|
|
367
|
-
type: "knowledge-artifact",
|
|
368
|
-
id: `artifact:${slug}`,
|
|
369
|
-
title: artifactTitle,
|
|
370
|
-
authors: [did],
|
|
371
|
-
version: 1,
|
|
372
|
-
confidence,
|
|
373
|
-
tags: tags?.length ? tags : undefined,
|
|
374
|
-
created: now,
|
|
375
|
-
lastModified: now,
|
|
376
|
-
modifiedBy: did,
|
|
377
|
-
provenance: [
|
|
378
|
-
{
|
|
379
|
-
agent: did,
|
|
380
|
-
action: "created",
|
|
381
|
-
timestamp: now,
|
|
382
|
-
message,
|
|
383
|
-
},
|
|
384
|
-
],
|
|
385
|
-
},
|
|
386
|
-
content: `\n${bodyContent}\n`,
|
|
387
|
-
};
|
|
388
|
-
}
|
|
389
|
-
const output = matter.stringify(fileData.content, fileData.data);
|
|
390
|
-
await writeFile(filePath, output, "utf-8");
|
|
391
|
-
return {
|
|
392
|
-
content: [
|
|
393
|
-
{
|
|
394
|
-
type: "text",
|
|
395
|
-
text: `${isNew ? "Created" : "Updated"} artifacts/${slug}.md (version ${version})`,
|
|
396
|
-
},
|
|
397
|
-
],
|
|
398
|
-
};
|
|
399
|
-
});
|
|
400
|
-
// --- Tool: awp_artifact_list ---
|
|
401
|
-
server.registerTool("awp_artifact_list", {
|
|
402
|
-
title: "List Knowledge Artifacts",
|
|
403
|
-
description: "List all knowledge artifacts in the workspace with metadata",
|
|
404
|
-
inputSchema: {
|
|
405
|
-
tag: z.string().optional().describe("Filter by tag"),
|
|
406
|
-
},
|
|
407
|
-
}, async ({ tag }) => {
|
|
408
|
-
const root = getWorkspaceRoot();
|
|
409
|
-
const artifactsDir = join(root, ARTIFACTS_DIR);
|
|
410
|
-
let files;
|
|
411
|
-
try {
|
|
412
|
-
files = await readdir(artifactsDir);
|
|
413
|
-
}
|
|
414
|
-
catch {
|
|
415
|
-
return {
|
|
416
|
-
content: [
|
|
417
|
-
{ type: "text", text: JSON.stringify({ artifacts: [] }, null, 2) },
|
|
418
|
-
],
|
|
419
|
-
};
|
|
420
|
-
}
|
|
421
|
-
const mdFiles = files.filter((f) => f.endsWith(".md")).sort();
|
|
422
|
-
const artifacts = [];
|
|
423
|
-
for (const f of mdFiles) {
|
|
424
|
-
try {
|
|
425
|
-
const raw = await readFile(join(artifactsDir, f), "utf-8");
|
|
426
|
-
const { data } = matter(raw);
|
|
427
|
-
if (data.type !== "knowledge-artifact")
|
|
428
|
-
continue;
|
|
429
|
-
if (tag && !data.tags?.some((t) => t.toLowerCase() === tag.toLowerCase())) {
|
|
430
|
-
continue;
|
|
431
|
-
}
|
|
432
|
-
artifacts.push({
|
|
433
|
-
slug: f.replace(/\.md$/, ""),
|
|
434
|
-
title: data.title,
|
|
435
|
-
version: data.version,
|
|
436
|
-
confidence: data.confidence,
|
|
437
|
-
tags: data.tags,
|
|
438
|
-
authors: data.authors,
|
|
439
|
-
lastModified: data.lastModified,
|
|
440
|
-
});
|
|
441
|
-
}
|
|
442
|
-
catch {
|
|
443
|
-
// Skip unparseable
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
return {
|
|
447
|
-
content: [
|
|
448
|
-
{
|
|
449
|
-
type: "text",
|
|
450
|
-
text: JSON.stringify({ artifacts }, null, 2),
|
|
451
|
-
},
|
|
452
|
-
],
|
|
453
|
-
};
|
|
454
|
-
});
|
|
455
|
-
// --- Tool: awp_artifact_search ---
|
|
456
|
-
server.registerTool("awp_artifact_search", {
|
|
457
|
-
title: "Search Knowledge Artifacts",
|
|
458
|
-
description: "Search artifacts by title, tags, or body content",
|
|
459
|
-
inputSchema: {
|
|
460
|
-
query: z.string().describe("Search query"),
|
|
461
|
-
},
|
|
462
|
-
}, async ({ query }) => {
|
|
463
|
-
const root = getWorkspaceRoot();
|
|
464
|
-
const artifactsDir = join(root, ARTIFACTS_DIR);
|
|
465
|
-
const queryLower = query.toLowerCase();
|
|
466
|
-
let files;
|
|
467
|
-
try {
|
|
468
|
-
files = await readdir(artifactsDir);
|
|
469
|
-
}
|
|
470
|
-
catch {
|
|
471
|
-
return {
|
|
472
|
-
content: [
|
|
473
|
-
{ type: "text", text: JSON.stringify({ results: [] }, null, 2) },
|
|
474
|
-
],
|
|
475
|
-
};
|
|
476
|
-
}
|
|
477
|
-
const mdFiles = files.filter((f) => f.endsWith(".md")).sort();
|
|
478
|
-
const results = [];
|
|
479
|
-
for (const f of mdFiles) {
|
|
480
|
-
try {
|
|
481
|
-
const raw = await readFile(join(artifactsDir, f), "utf-8");
|
|
482
|
-
const { data, content } = matter(raw);
|
|
483
|
-
if (data.type !== "knowledge-artifact")
|
|
484
|
-
continue;
|
|
485
|
-
const titleMatch = data.title?.toLowerCase().includes(queryLower);
|
|
486
|
-
const tagMatch = data.tags?.some((t) => t.toLowerCase().includes(queryLower));
|
|
487
|
-
const bodyMatch = content.toLowerCase().includes(queryLower);
|
|
488
|
-
if (titleMatch || tagMatch || bodyMatch) {
|
|
489
|
-
results.push({
|
|
490
|
-
slug: f.replace(/\.md$/, ""),
|
|
491
|
-
title: data.title,
|
|
492
|
-
version: data.version,
|
|
493
|
-
confidence: data.confidence,
|
|
494
|
-
tags: data.tags,
|
|
495
|
-
matchedIn: [
|
|
496
|
-
titleMatch && "title",
|
|
497
|
-
tagMatch && "tags",
|
|
498
|
-
bodyMatch && "body",
|
|
499
|
-
].filter(Boolean),
|
|
500
|
-
});
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
catch {
|
|
504
|
-
// Skip
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
return {
|
|
508
|
-
content: [
|
|
509
|
-
{
|
|
510
|
-
type: "text",
|
|
511
|
-
text: JSON.stringify({ results }, null, 2),
|
|
512
|
-
},
|
|
513
|
-
],
|
|
514
|
-
};
|
|
515
|
-
});
|
|
516
|
-
// --- Tool: awp_workspace_status ---
|
|
517
|
-
server.registerTool("awp_workspace_status", {
|
|
518
|
-
title: "Workspace Status",
|
|
519
|
-
description: "Get AWP workspace health status — manifest info, file presence, memory stats, artifact count",
|
|
520
|
-
inputSchema: {},
|
|
521
|
-
}, async () => {
|
|
522
|
-
const root = getWorkspaceRoot();
|
|
523
|
-
const status = { root };
|
|
524
|
-
// Manifest
|
|
525
|
-
try {
|
|
526
|
-
const manifestRaw = await readFile(join(root, ".awp", "workspace.json"), "utf-8");
|
|
527
|
-
status.manifest = JSON.parse(manifestRaw);
|
|
528
|
-
}
|
|
529
|
-
catch {
|
|
530
|
-
status.manifest = null;
|
|
531
|
-
status.error = "No .awp/workspace.json found";
|
|
532
|
-
}
|
|
533
|
-
// File presence
|
|
534
|
-
const fileChecks = [
|
|
535
|
-
"IDENTITY.md",
|
|
536
|
-
"SOUL.md",
|
|
537
|
-
"AGENTS.md",
|
|
538
|
-
"USER.md",
|
|
539
|
-
"TOOLS.md",
|
|
540
|
-
"HEARTBEAT.md",
|
|
541
|
-
"MEMORY.md",
|
|
542
|
-
];
|
|
543
|
-
status.files = {};
|
|
544
|
-
for (const f of fileChecks) {
|
|
545
|
-
status.files[f] = await fileExists(join(root, f));
|
|
546
|
-
}
|
|
547
|
-
// Memory stats
|
|
548
|
-
try {
|
|
549
|
-
const memDir = join(root, MEMORY_DIR);
|
|
550
|
-
const files = await readdir(memDir);
|
|
551
|
-
const mdFiles = files.filter((f) => f.endsWith(".md"));
|
|
552
|
-
status.memory = {
|
|
553
|
-
logCount: mdFiles.length,
|
|
554
|
-
latest: mdFiles.sort().reverse()[0] || null,
|
|
555
|
-
};
|
|
556
|
-
}
|
|
557
|
-
catch {
|
|
558
|
-
status.memory = { logCount: 0, latest: null };
|
|
559
|
-
}
|
|
560
|
-
// Artifact stats
|
|
561
|
-
try {
|
|
562
|
-
const artDir = join(root, ARTIFACTS_DIR);
|
|
563
|
-
const files = await readdir(artDir);
|
|
564
|
-
const mdFiles = files.filter((f) => f.endsWith(".md"));
|
|
565
|
-
status.artifacts = { count: mdFiles.length };
|
|
566
|
-
}
|
|
567
|
-
catch {
|
|
568
|
-
status.artifacts = { count: 0 };
|
|
569
|
-
}
|
|
570
|
-
return {
|
|
571
|
-
content: [
|
|
572
|
-
{ type: "text", text: JSON.stringify(status, null, 2) },
|
|
573
|
-
],
|
|
574
|
-
};
|
|
575
|
-
});
|
|
27
|
+
// Register all tool groups
|
|
28
|
+
registerIdentityTools(server);
|
|
29
|
+
registerMemoryTools(server);
|
|
30
|
+
registerArtifactTools(server);
|
|
31
|
+
registerStatusTools(server);
|
|
32
|
+
registerReputationTools(server);
|
|
33
|
+
registerContractTools(server);
|
|
34
|
+
registerProjectTools(server);
|
|
35
|
+
registerTaskTools(server);
|
|
36
|
+
registerConfigTools(server);
|
|
37
|
+
registerSwarmTools(server);
|
|
576
38
|
// Start the server
|
|
577
39
|
const transport = new StdioServerTransport();
|
|
578
40
|
await server.connect(transport);
|