@agent-workspace/mcp-server 0.4.0 → 0.6.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/dist/index.d.ts +5 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -1836
- 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 +3 -2
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { readFile, writeFile, readdir, mkdir, access } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import matter from "gray-matter";
|
|
4
|
+
import * as z from "zod";
|
|
5
|
+
import { AWP_VERSION, CDP_VERSION, PROJECTS_DIR } from "@agent-workspace/core";
|
|
6
|
+
import { getWorkspaceRoot, getAgentDid } from "@agent-workspace/utils";
|
|
7
|
+
/**
|
|
8
|
+
* Check if a file exists at the given path.
|
|
9
|
+
*/
|
|
10
|
+
async function fileExists(path) {
|
|
11
|
+
try {
|
|
12
|
+
await access(path);
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Register project-related tools: create, list, status
|
|
21
|
+
*/
|
|
22
|
+
export function registerProjectTools(server) {
|
|
23
|
+
// --- Tool: awp_project_create ---
|
|
24
|
+
server.registerTool("awp_project_create", {
|
|
25
|
+
title: "Create Project",
|
|
26
|
+
description: "Create a new coordination project with member roles and optional reputation gates.",
|
|
27
|
+
inputSchema: {
|
|
28
|
+
slug: z.string().describe("Project slug (e.g., 'q3-product-launch')"),
|
|
29
|
+
title: z.string().optional().describe("Project title"),
|
|
30
|
+
deadline: z.string().optional().describe("Deadline (ISO 8601 or YYYY-MM-DD)"),
|
|
31
|
+
tags: z.array(z.string()).optional().describe("Classification tags"),
|
|
32
|
+
},
|
|
33
|
+
}, async ({ slug, title, deadline, tags }) => {
|
|
34
|
+
const root = getWorkspaceRoot();
|
|
35
|
+
const projDir = join(root, PROJECTS_DIR);
|
|
36
|
+
await mkdir(projDir, { recursive: true });
|
|
37
|
+
const filePath = join(projDir, `${slug}.md`);
|
|
38
|
+
if (await fileExists(filePath)) {
|
|
39
|
+
return {
|
|
40
|
+
content: [{ type: "text", text: `Project "${slug}" already exists.` }],
|
|
41
|
+
isError: true,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const did = await getAgentDid(root);
|
|
45
|
+
const now = new Date().toISOString();
|
|
46
|
+
const projectTitle = title ||
|
|
47
|
+
slug
|
|
48
|
+
.split("-")
|
|
49
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
50
|
+
.join(" ");
|
|
51
|
+
const data = {
|
|
52
|
+
awp: AWP_VERSION,
|
|
53
|
+
cdp: CDP_VERSION,
|
|
54
|
+
type: "project",
|
|
55
|
+
id: `project:${slug}`,
|
|
56
|
+
title: projectTitle,
|
|
57
|
+
status: "active",
|
|
58
|
+
owner: did,
|
|
59
|
+
created: now,
|
|
60
|
+
members: [{ did, role: "lead", slug: "self" }],
|
|
61
|
+
taskCount: 0,
|
|
62
|
+
completedCount: 0,
|
|
63
|
+
};
|
|
64
|
+
if (deadline)
|
|
65
|
+
data.deadline = deadline;
|
|
66
|
+
if (tags?.length)
|
|
67
|
+
data.tags = tags;
|
|
68
|
+
const body = `\n# ${projectTitle}\n\n`;
|
|
69
|
+
const output = matter.stringify(body, data);
|
|
70
|
+
await writeFile(filePath, output, "utf-8");
|
|
71
|
+
return {
|
|
72
|
+
content: [{ type: "text", text: `Created projects/${slug}.md (status: active)` }],
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
// --- Tool: awp_project_list ---
|
|
76
|
+
server.registerTool("awp_project_list", {
|
|
77
|
+
title: "List Projects",
|
|
78
|
+
description: "List all projects in the workspace with status and task progress.",
|
|
79
|
+
inputSchema: {
|
|
80
|
+
status: z
|
|
81
|
+
.string()
|
|
82
|
+
.optional()
|
|
83
|
+
.describe("Filter by status (draft, active, paused, completed, archived)"),
|
|
84
|
+
},
|
|
85
|
+
}, async ({ status: statusFilter }) => {
|
|
86
|
+
const root = getWorkspaceRoot();
|
|
87
|
+
const projDir = join(root, PROJECTS_DIR);
|
|
88
|
+
let files;
|
|
89
|
+
try {
|
|
90
|
+
files = await readdir(projDir);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return {
|
|
94
|
+
content: [{ type: "text", text: JSON.stringify({ projects: [] }, null, 2) }],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const projects = [];
|
|
98
|
+
for (const f of files.filter((f) => f.endsWith(".md")).sort()) {
|
|
99
|
+
try {
|
|
100
|
+
const raw = await readFile(join(projDir, f), "utf-8");
|
|
101
|
+
const { data } = matter(raw);
|
|
102
|
+
if (data.type !== "project")
|
|
103
|
+
continue;
|
|
104
|
+
if (statusFilter && data.status !== statusFilter)
|
|
105
|
+
continue;
|
|
106
|
+
const members = data.members;
|
|
107
|
+
projects.push({
|
|
108
|
+
slug: f.replace(/\.md$/, ""),
|
|
109
|
+
title: data.title,
|
|
110
|
+
status: data.status,
|
|
111
|
+
taskCount: data.taskCount || 0,
|
|
112
|
+
completedCount: data.completedCount || 0,
|
|
113
|
+
deadline: data.deadline,
|
|
114
|
+
owner: data.owner,
|
|
115
|
+
memberCount: members?.length || 0,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
/* skip */
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
content: [{ type: "text", text: JSON.stringify({ projects }, null, 2) }],
|
|
124
|
+
};
|
|
125
|
+
});
|
|
126
|
+
// --- Tool: awp_project_status ---
|
|
127
|
+
server.registerTool("awp_project_status", {
|
|
128
|
+
title: "Project Status",
|
|
129
|
+
description: "Get detailed project status including members, tasks, and progress.",
|
|
130
|
+
inputSchema: {
|
|
131
|
+
slug: z.string().describe("Project slug"),
|
|
132
|
+
},
|
|
133
|
+
}, async ({ slug }) => {
|
|
134
|
+
const root = getWorkspaceRoot();
|
|
135
|
+
const filePath = join(root, PROJECTS_DIR, `${slug}.md`);
|
|
136
|
+
try {
|
|
137
|
+
const raw = await readFile(filePath, "utf-8");
|
|
138
|
+
const { data, content } = matter(raw);
|
|
139
|
+
// Load tasks
|
|
140
|
+
const tasks = [];
|
|
141
|
+
try {
|
|
142
|
+
const taskDir = join(root, PROJECTS_DIR, slug, "tasks");
|
|
143
|
+
const taskFiles = await readdir(taskDir);
|
|
144
|
+
for (const tf of taskFiles.filter((t) => t.endsWith(".md")).sort()) {
|
|
145
|
+
try {
|
|
146
|
+
const tRaw = await readFile(join(taskDir, tf), "utf-8");
|
|
147
|
+
const { data: tData } = matter(tRaw);
|
|
148
|
+
const blockedBy = tData.blockedBy;
|
|
149
|
+
tasks.push({
|
|
150
|
+
slug: tf.replace(/\.md$/, ""),
|
|
151
|
+
title: tData.title,
|
|
152
|
+
status: tData.status,
|
|
153
|
+
assigneeSlug: tData.assigneeSlug,
|
|
154
|
+
priority: tData.priority,
|
|
155
|
+
deadline: tData.deadline,
|
|
156
|
+
blockedBy: blockedBy || [],
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
/* skip */
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
/* no tasks */
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
content: [
|
|
169
|
+
{
|
|
170
|
+
type: "text",
|
|
171
|
+
text: JSON.stringify({ frontmatter: data, body: content.trim(), tasks }, null, 2),
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
return {
|
|
178
|
+
content: [{ type: "text", text: `Project "${slug}" not found.` }],
|
|
179
|
+
isError: true,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/tools/project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reputation.d.ts","sourceRoot":"","sources":["../../src/tools/reputation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAczE;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA8N/D"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { readFile, writeFile, readdir, mkdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import matter from "gray-matter";
|
|
4
|
+
import * as z from "zod";
|
|
5
|
+
import { AWP_VERSION, RDP_VERSION, REPUTATION_DIR } from "@agent-workspace/core";
|
|
6
|
+
import { getWorkspaceRoot, getAgentDid, computeDecayedScore, updateDimension, } from "@agent-workspace/utils";
|
|
7
|
+
/**
|
|
8
|
+
* Register reputation-related tools: query, signal
|
|
9
|
+
*/
|
|
10
|
+
export function registerReputationTools(server) {
|
|
11
|
+
// --- Tool: awp_reputation_query ---
|
|
12
|
+
server.registerTool("awp_reputation_query", {
|
|
13
|
+
title: "Query Reputation",
|
|
14
|
+
description: "Query an agent's reputation profile. Returns multi-dimensional scores with decay applied. Omit slug to list all tracked agents.",
|
|
15
|
+
inputSchema: {
|
|
16
|
+
slug: z.string().optional().describe("Agent reputation slug (omit to list all)"),
|
|
17
|
+
dimension: z.string().optional().describe("Filter by dimension"),
|
|
18
|
+
domain: z.string().optional().describe("Filter by domain competence"),
|
|
19
|
+
},
|
|
20
|
+
}, async ({ slug, dimension, domain }) => {
|
|
21
|
+
const root = getWorkspaceRoot();
|
|
22
|
+
if (!slug) {
|
|
23
|
+
// List all profiles
|
|
24
|
+
const repDir = join(root, REPUTATION_DIR);
|
|
25
|
+
let files;
|
|
26
|
+
try {
|
|
27
|
+
files = await readdir(repDir);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return {
|
|
31
|
+
content: [{ type: "text", text: JSON.stringify({ profiles: [] }, null, 2) }],
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const profiles = [];
|
|
35
|
+
for (const f of files.filter((f) => f.endsWith(".md")).sort()) {
|
|
36
|
+
try {
|
|
37
|
+
const raw = await readFile(join(repDir, f), "utf-8");
|
|
38
|
+
const { data } = matter(raw);
|
|
39
|
+
if (data.type !== "reputation-profile")
|
|
40
|
+
continue;
|
|
41
|
+
const signals = data.signals;
|
|
42
|
+
const dimensions = data.dimensions;
|
|
43
|
+
const domainCompetence = data.domainCompetence;
|
|
44
|
+
profiles.push({
|
|
45
|
+
slug: f.replace(/\.md$/, ""),
|
|
46
|
+
agentName: data.agentName,
|
|
47
|
+
agentDid: data.agentDid,
|
|
48
|
+
signalCount: signals?.length || 0,
|
|
49
|
+
dimensions: Object.keys(dimensions || {}),
|
|
50
|
+
domains: Object.keys(domainCompetence || {}),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
/* skip */
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
content: [{ type: "text", text: JSON.stringify({ profiles }, null, 2) }],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// Read specific profile
|
|
62
|
+
const path = join(root, REPUTATION_DIR, `${slug}.md`);
|
|
63
|
+
try {
|
|
64
|
+
const raw = await readFile(path, "utf-8");
|
|
65
|
+
const { data, content } = matter(raw);
|
|
66
|
+
// Apply decay to scores
|
|
67
|
+
const now = new Date();
|
|
68
|
+
const applyDecay = (dim) => {
|
|
69
|
+
if (!dim?.lastSignal)
|
|
70
|
+
return dim;
|
|
71
|
+
const decayedScore = computeDecayedScore(dim, now);
|
|
72
|
+
return { ...dim, decayedScore };
|
|
73
|
+
};
|
|
74
|
+
const result = { ...data, body: content.trim() };
|
|
75
|
+
// Apply decay to dimensions
|
|
76
|
+
const dimensions = data.dimensions;
|
|
77
|
+
if (dimensions) {
|
|
78
|
+
result.dimensions = {};
|
|
79
|
+
const resultDimensions = result.dimensions;
|
|
80
|
+
for (const [name, dim] of Object.entries(dimensions)) {
|
|
81
|
+
if (dimension && name !== dimension)
|
|
82
|
+
continue;
|
|
83
|
+
resultDimensions[name] = applyDecay(dim);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const domainCompetence = data.domainCompetence;
|
|
87
|
+
if (domainCompetence) {
|
|
88
|
+
result.domainCompetence = {};
|
|
89
|
+
const resultDomains = result.domainCompetence;
|
|
90
|
+
for (const [name, dim] of Object.entries(domainCompetence)) {
|
|
91
|
+
if (domain && name !== domain)
|
|
92
|
+
continue;
|
|
93
|
+
resultDomains[name] = applyDecay(dim);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return {
|
|
102
|
+
content: [{ type: "text", text: `Reputation profile "${slug}" not found.` }],
|
|
103
|
+
isError: true,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
// --- Tool: awp_reputation_signal ---
|
|
108
|
+
server.registerTool("awp_reputation_signal", {
|
|
109
|
+
title: "Log Reputation Signal",
|
|
110
|
+
description: "Log a reputation signal for an agent. Creates the profile if it doesn't exist (requires agentDid and agentName for new profiles).",
|
|
111
|
+
inputSchema: {
|
|
112
|
+
slug: z.string().describe("Agent reputation slug"),
|
|
113
|
+
dimension: z
|
|
114
|
+
.string()
|
|
115
|
+
.describe("Dimension (reliability, epistemic-hygiene, coordination, domain-competence)"),
|
|
116
|
+
score: z.number().min(0).max(1).describe("Score (0.0-1.0)"),
|
|
117
|
+
domain: z.string().optional().describe("Domain (required for domain-competence)"),
|
|
118
|
+
evidence: z.string().optional().describe("Evidence reference"),
|
|
119
|
+
message: z.string().optional().describe("Human-readable note"),
|
|
120
|
+
agentDid: z.string().optional().describe("Agent DID (required for new profiles)"),
|
|
121
|
+
agentName: z.string().optional().describe("Agent name (required for new profiles)"),
|
|
122
|
+
},
|
|
123
|
+
}, async ({ slug, dimension: dim, score, domain, evidence, message, agentDid: newDid, agentName: newName, }) => {
|
|
124
|
+
const root = getWorkspaceRoot();
|
|
125
|
+
const repDir = join(root, REPUTATION_DIR);
|
|
126
|
+
await mkdir(repDir, { recursive: true });
|
|
127
|
+
const filePath = join(repDir, `${slug}.md`);
|
|
128
|
+
const sourceDid = await getAgentDid(root);
|
|
129
|
+
const now = new Date();
|
|
130
|
+
const timestamp = now.toISOString();
|
|
131
|
+
const signal = {
|
|
132
|
+
source: sourceDid,
|
|
133
|
+
dimension: dim,
|
|
134
|
+
score,
|
|
135
|
+
timestamp,
|
|
136
|
+
};
|
|
137
|
+
if (domain)
|
|
138
|
+
signal.domain = domain;
|
|
139
|
+
if (evidence)
|
|
140
|
+
signal.evidence = evidence;
|
|
141
|
+
if (message)
|
|
142
|
+
signal.message = message;
|
|
143
|
+
let isNew = false;
|
|
144
|
+
let fileData;
|
|
145
|
+
try {
|
|
146
|
+
const raw = await readFile(filePath, "utf-8");
|
|
147
|
+
fileData = matter(raw);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// New profile
|
|
151
|
+
if (!newDid || !newName) {
|
|
152
|
+
return {
|
|
153
|
+
content: [
|
|
154
|
+
{
|
|
155
|
+
type: "text",
|
|
156
|
+
text: "Error: agentDid and agentName required for new profiles.",
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
isError: true,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
isNew = true;
|
|
163
|
+
fileData = {
|
|
164
|
+
data: {
|
|
165
|
+
awp: AWP_VERSION,
|
|
166
|
+
rdp: RDP_VERSION,
|
|
167
|
+
type: "reputation-profile",
|
|
168
|
+
id: `reputation:${slug}`,
|
|
169
|
+
agentDid: newDid,
|
|
170
|
+
agentName: newName,
|
|
171
|
+
lastUpdated: timestamp,
|
|
172
|
+
dimensions: {},
|
|
173
|
+
domainCompetence: {},
|
|
174
|
+
signals: [],
|
|
175
|
+
},
|
|
176
|
+
content: `\n# ${newName} — Reputation Profile\n\nTracked since ${timestamp.split("T")[0]}.\n`,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
fileData.data.lastUpdated = timestamp;
|
|
180
|
+
const signals = fileData.data.signals;
|
|
181
|
+
signals.push(signal);
|
|
182
|
+
if (!fileData.data.dimensions)
|
|
183
|
+
fileData.data.dimensions = {};
|
|
184
|
+
if (!fileData.data.domainCompetence)
|
|
185
|
+
fileData.data.domainCompetence = {};
|
|
186
|
+
const dimensions = fileData.data.dimensions;
|
|
187
|
+
const domainCompetence = fileData.data.domainCompetence;
|
|
188
|
+
if (dim === "domain-competence" && domain) {
|
|
189
|
+
domainCompetence[domain] = updateDimension(domainCompetence[domain], score, now);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
dimensions[dim] = updateDimension(dimensions[dim], score, now);
|
|
193
|
+
}
|
|
194
|
+
const output = matter.stringify(fileData.content, fileData.data);
|
|
195
|
+
await writeFile(filePath, output, "utf-8");
|
|
196
|
+
return {
|
|
197
|
+
content: [
|
|
198
|
+
{
|
|
199
|
+
type: "text",
|
|
200
|
+
text: `${isNew ? "Created" : "Updated"} reputation/${slug}.md — ${dim}${domain ? `:${domain}` : ""}: ${score}`,
|
|
201
|
+
},
|
|
202
|
+
],
|
|
203
|
+
};
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=reputation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reputation.js","sourceRoot":"","sources":["../../src/tools/reputation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/tools/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAyBzE;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAmN3D"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { readFile, readdir, access } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import matter from "gray-matter";
|
|
4
|
+
import { MEMORY_DIR, ARTIFACTS_DIR, REPUTATION_DIR, CONTRACTS_DIR, PROJECTS_DIR, } from "@agent-workspace/core";
|
|
5
|
+
import { getWorkspaceRoot } from "@agent-workspace/utils";
|
|
6
|
+
/**
|
|
7
|
+
* Check if a file exists at the given path.
|
|
8
|
+
*/
|
|
9
|
+
async function fileExists(path) {
|
|
10
|
+
try {
|
|
11
|
+
await access(path);
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Register status-related tools: workspace_status
|
|
20
|
+
*/
|
|
21
|
+
export function registerStatusTools(server) {
|
|
22
|
+
// --- Tool: awp_workspace_status ---
|
|
23
|
+
server.registerTool("awp_workspace_status", {
|
|
24
|
+
title: "Workspace Status",
|
|
25
|
+
description: "Get AWP workspace health status — manifest, files, projects, tasks, reputation, contracts, artifacts, memory, health warnings",
|
|
26
|
+
inputSchema: {},
|
|
27
|
+
}, async () => {
|
|
28
|
+
const root = getWorkspaceRoot();
|
|
29
|
+
const status = { root };
|
|
30
|
+
// Manifest
|
|
31
|
+
try {
|
|
32
|
+
const manifestRaw = await readFile(join(root, ".awp", "workspace.json"), "utf-8");
|
|
33
|
+
status.manifest = JSON.parse(manifestRaw);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
status.manifest = null;
|
|
37
|
+
status.error = "No .awp/workspace.json found";
|
|
38
|
+
}
|
|
39
|
+
// File presence
|
|
40
|
+
const fileChecks = [
|
|
41
|
+
"IDENTITY.md",
|
|
42
|
+
"SOUL.md",
|
|
43
|
+
"AGENTS.md",
|
|
44
|
+
"USER.md",
|
|
45
|
+
"TOOLS.md",
|
|
46
|
+
"HEARTBEAT.md",
|
|
47
|
+
"MEMORY.md",
|
|
48
|
+
];
|
|
49
|
+
status.files = {};
|
|
50
|
+
const filesStatus = status.files;
|
|
51
|
+
for (const f of fileChecks) {
|
|
52
|
+
filesStatus[f] = await fileExists(join(root, f));
|
|
53
|
+
}
|
|
54
|
+
// Memory stats
|
|
55
|
+
try {
|
|
56
|
+
const memDir = join(root, MEMORY_DIR);
|
|
57
|
+
const files = await readdir(memDir);
|
|
58
|
+
const mdFiles = files.filter((f) => f.endsWith(".md"));
|
|
59
|
+
status.memory = {
|
|
60
|
+
logCount: mdFiles.length,
|
|
61
|
+
latest: mdFiles.sort().reverse()[0] || null,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
status.memory = { logCount: 0, latest: null };
|
|
66
|
+
}
|
|
67
|
+
// Artifact stats
|
|
68
|
+
try {
|
|
69
|
+
const artDir = join(root, ARTIFACTS_DIR);
|
|
70
|
+
const files = await readdir(artDir);
|
|
71
|
+
const mdFiles = files.filter((f) => f.endsWith(".md"));
|
|
72
|
+
status.artifacts = { count: mdFiles.length };
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
status.artifacts = { count: 0 };
|
|
76
|
+
}
|
|
77
|
+
// Reputation stats
|
|
78
|
+
try {
|
|
79
|
+
const repDir = join(root, REPUTATION_DIR);
|
|
80
|
+
const files = await readdir(repDir);
|
|
81
|
+
const mdFiles = files.filter((f) => f.endsWith(".md"));
|
|
82
|
+
status.reputation = { count: mdFiles.length };
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
status.reputation = { count: 0 };
|
|
86
|
+
}
|
|
87
|
+
// Contract stats
|
|
88
|
+
try {
|
|
89
|
+
const conDir = join(root, CONTRACTS_DIR);
|
|
90
|
+
const files = await readdir(conDir);
|
|
91
|
+
const mdFiles = files.filter((f) => f.endsWith(".md"));
|
|
92
|
+
status.contracts = { count: mdFiles.length };
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
status.contracts = { count: 0 };
|
|
96
|
+
}
|
|
97
|
+
// Project + task stats
|
|
98
|
+
const projectsSummary = [];
|
|
99
|
+
let totalTasks = 0;
|
|
100
|
+
let activeTasks = 0;
|
|
101
|
+
try {
|
|
102
|
+
const projDir = join(root, PROJECTS_DIR);
|
|
103
|
+
const projFiles = await readdir(projDir);
|
|
104
|
+
const mdFiles = projFiles.filter((f) => f.endsWith(".md")).sort();
|
|
105
|
+
for (const f of mdFiles) {
|
|
106
|
+
try {
|
|
107
|
+
const raw = await readFile(join(projDir, f), "utf-8");
|
|
108
|
+
const { data } = matter(raw);
|
|
109
|
+
if (data.type !== "project")
|
|
110
|
+
continue;
|
|
111
|
+
const slug = f.replace(/\.md$/, "");
|
|
112
|
+
const projInfo = {
|
|
113
|
+
slug,
|
|
114
|
+
title: data.title,
|
|
115
|
+
status: data.status,
|
|
116
|
+
taskCount: data.taskCount || 0,
|
|
117
|
+
completedCount: data.completedCount || 0,
|
|
118
|
+
};
|
|
119
|
+
if (data.deadline)
|
|
120
|
+
projInfo.deadline = data.deadline;
|
|
121
|
+
projectsSummary.push(projInfo);
|
|
122
|
+
totalTasks += data.taskCount || 0;
|
|
123
|
+
// Count active tasks
|
|
124
|
+
try {
|
|
125
|
+
const taskDir = join(projDir, slug, "tasks");
|
|
126
|
+
const taskFiles = await readdir(taskDir);
|
|
127
|
+
for (const tf of taskFiles.filter((t) => t.endsWith(".md"))) {
|
|
128
|
+
try {
|
|
129
|
+
const tRaw = await readFile(join(taskDir, tf), "utf-8");
|
|
130
|
+
const { data: tData } = matter(tRaw);
|
|
131
|
+
if (tData.status === "in-progress" ||
|
|
132
|
+
tData.status === "blocked" ||
|
|
133
|
+
tData.status === "review") {
|
|
134
|
+
activeTasks++;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
/* skip */
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
/* no tasks dir */
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
/* skip */
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
/* no projects dir */
|
|
153
|
+
}
|
|
154
|
+
status.projects = {
|
|
155
|
+
count: projectsSummary.length,
|
|
156
|
+
totalTasks,
|
|
157
|
+
activeTasks,
|
|
158
|
+
list: projectsSummary,
|
|
159
|
+
};
|
|
160
|
+
// Health warnings
|
|
161
|
+
const warnings = [];
|
|
162
|
+
const now = new Date();
|
|
163
|
+
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
164
|
+
// Check required files
|
|
165
|
+
if (!filesStatus["IDENTITY.md"])
|
|
166
|
+
warnings.push("IDENTITY.md missing");
|
|
167
|
+
if (!filesStatus["SOUL.md"])
|
|
168
|
+
warnings.push("SOUL.md missing");
|
|
169
|
+
// Check contract deadlines
|
|
170
|
+
try {
|
|
171
|
+
const conDir = join(root, CONTRACTS_DIR);
|
|
172
|
+
const conFiles = await readdir(conDir);
|
|
173
|
+
for (const f of conFiles.filter((f) => f.endsWith(".md"))) {
|
|
174
|
+
try {
|
|
175
|
+
const raw = await readFile(join(conDir, f), "utf-8");
|
|
176
|
+
const { data } = matter(raw);
|
|
177
|
+
if (data.deadline && (data.status === "active" || data.status === "draft")) {
|
|
178
|
+
if (new Date(data.deadline) < now) {
|
|
179
|
+
warnings.push(`Contract "${f.replace(/\.md$/, "")}" is past deadline`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
/* skip */
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
/* no contracts */
|
|
190
|
+
}
|
|
191
|
+
// Check reputation decay
|
|
192
|
+
try {
|
|
193
|
+
const repDir = join(root, REPUTATION_DIR);
|
|
194
|
+
const repFiles = await readdir(repDir);
|
|
195
|
+
for (const f of repFiles.filter((f) => f.endsWith(".md"))) {
|
|
196
|
+
try {
|
|
197
|
+
const raw = await readFile(join(repDir, f), "utf-8");
|
|
198
|
+
const { data } = matter(raw);
|
|
199
|
+
if (data.lastUpdated) {
|
|
200
|
+
const daysSince = Math.floor((now.getTime() - new Date(data.lastUpdated).getTime()) / MS_PER_DAY);
|
|
201
|
+
if (daysSince > 30) {
|
|
202
|
+
warnings.push(`${f.replace(/\.md$/, "")} reputation decaying (no signal in ${daysSince} days)`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
/* skip */
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
/* no reputation */
|
|
213
|
+
}
|
|
214
|
+
status.health = {
|
|
215
|
+
warnings,
|
|
216
|
+
ok: warnings.length === 0,
|
|
217
|
+
};
|
|
218
|
+
return {
|
|
219
|
+
content: [{ type: "text", text: JSON.stringify(status, null, 2) }],
|
|
220
|
+
};
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=status.js.map
|