archgen-mcp 0.1.1 → 0.1.2
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 +14 -0
- package/assets/briefs/survey.md +1 -1
- package/assets/briefs/verifier.md +2 -1
- package/assets/references/artifact-templates.md +22 -0
- package/assets/references/mcp-and-skills.md +3 -1
- package/assets/templates/architecture.yaml +9 -16
- package/assets/templates/tasks.yaml +2 -2
- package/package.json +1 -1
- package/src/core/doc-navigator.mjs +24 -5
- package/src/core/refs.mjs +89 -16
- package/src/envelope.mjs +98 -1
- package/src/tools/codegraph.mjs +20 -1
- package/src/tools/docs.mjs +55 -10
- package/src/tools/help.mjs +13 -3
- package/src/tools/plan.mjs +68 -3
- package/src/tools/refs.mjs +78 -7
- package/src/tools/registry.mjs +15 -1
- package/src/tools/setup.mjs +53 -16
- package/src/tools/skills.mjs +135 -37
- package/src/tools/tasks.mjs +68 -3
package/src/tools/tasks.mjs
CHANGED
|
@@ -11,6 +11,7 @@ import { loadAsset } from '../context.mjs';
|
|
|
11
11
|
import { setTaskStatus, STATUSES } from '../core/status-mutator.mjs';
|
|
12
12
|
import { writeResumeSnapshot } from '../core/resume-snapshot.mjs';
|
|
13
13
|
import { invalidInput } from '../core/errors.mjs';
|
|
14
|
+
import { moreMeta, project, withMeta } from '../envelope.mjs';
|
|
14
15
|
import { resolveSlugInput, ScopeError } from '../core/scope.mjs';
|
|
15
16
|
import { dirname, join } from 'node:path';
|
|
16
17
|
|
|
@@ -40,13 +41,15 @@ const ACTION_DESC = 'next | set_status | list | snapshot | contract — see arch
|
|
|
40
41
|
const schema = z.object({
|
|
41
42
|
action: z.enum(['next', 'set_status', 'list', 'snapshot', 'contract']).describe(ACTION_DESC),
|
|
42
43
|
tasksYaml: z.string().optional().describe('Absolute path to tasks.yaml. Required for next, set_status and list.'),
|
|
43
|
-
taskId: z.string().optional().describe('Task id (set_status).'),
|
|
44
|
+
taskId: z.string().optional().describe('Task id (set_status, contract). ONE task (list, next).'),
|
|
44
45
|
status: z.enum(STATUSES).optional().describe('New status (set_status).'),
|
|
45
46
|
force: z.boolean().optional().describe('Allow reopening a done task (set_status).'),
|
|
46
47
|
filterStatus: z.string().optional().describe('Filter by status (list).'),
|
|
47
48
|
slugDir: z.string().optional().describe('The .archgen/<slug>/ directory (contract) — locates the plan docs.'),
|
|
48
49
|
codeStandardsPath: z.string().optional().describe('Path to the code-standards reference (contract).'),
|
|
49
50
|
module: z.string().optional().describe('Filter by module path fragment (list).'),
|
|
51
|
+
limit: z.number().int().positive().optional().describe('Max items to return. Default 50.'),
|
|
52
|
+
offset: z.number().int().nonnegative().optional().describe('Skip this many items.'),
|
|
50
53
|
projectRoot: projectRootArg,
|
|
51
54
|
});
|
|
52
55
|
|
|
@@ -74,10 +77,37 @@ export function registerTaskTools(server) {
|
|
|
74
77
|
}
|
|
75
78
|
case 'list': {
|
|
76
79
|
if (!args.tasksYaml) throw invalidInput('tasksYaml is required for list', { action });
|
|
77
|
-
|
|
80
|
+
const listed = listTasks(ctx.contain(args.tasksYaml), {
|
|
78
81
|
status: args.filterStatus ?? null,
|
|
79
82
|
module: args.module ?? null,
|
|
80
83
|
});
|
|
84
|
+
// ONE task, when the caller named one.
|
|
85
|
+
if (args.taskId) {
|
|
86
|
+
const one = (listed.tasks ?? []).find((t) => t.id === args.taskId);
|
|
87
|
+
if (!one) {
|
|
88
|
+
throw invalidInput(`no task '${args.taskId}' in ${args.tasksYaml}`, {
|
|
89
|
+
action,
|
|
90
|
+
taskId: args.taskId,
|
|
91
|
+
available: (listed.tasks ?? []).map((t) => t.id),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return { task: one, tasks: [one] };
|
|
95
|
+
}
|
|
96
|
+
const p = project(listed.tasks ?? [], {
|
|
97
|
+
limit: args.limit,
|
|
98
|
+
offset: args.offset,
|
|
99
|
+
next: `archgen_tasks{action:'list',tasksYaml:'${args.tasksYaml}',limit:${args.limit ?? 50},offset:${(args.offset ?? 0) + (args.limit ?? 50)}}`,
|
|
100
|
+
});
|
|
101
|
+
return withMeta(
|
|
102
|
+
{ ...listed, tasks: p.items },
|
|
103
|
+
moreMeta({
|
|
104
|
+
total: p.total,
|
|
105
|
+
returned: p.returned,
|
|
106
|
+
next: p.next,
|
|
107
|
+
available: { tasks: p.total },
|
|
108
|
+
more: `archgen_tasks{action:'list',tasksYaml:'${args.tasksYaml}',taskId:'<one task>'}`,
|
|
109
|
+
}),
|
|
110
|
+
);
|
|
81
111
|
}
|
|
82
112
|
case 'snapshot': {
|
|
83
113
|
if (!args.tasksYaml) throw invalidInput('tasksYaml is required for snapshot', { action });
|
|
@@ -196,7 +226,42 @@ export function registerTaskTools(server) {
|
|
|
196
226
|
}
|
|
197
227
|
case 'next': {
|
|
198
228
|
if (!args.tasksYaml) throw invalidInput('tasksYaml is required for next', { action });
|
|
199
|
-
|
|
229
|
+
const resolved = resolveWaves(ctx.contain(args.tasksYaml));
|
|
230
|
+
// ONE wave, when the caller named a task: "which wave is this in?"
|
|
231
|
+
if (args.taskId) {
|
|
232
|
+
const index = resolved.waves.findIndex((w) => w.some((t) => t.id === args.taskId));
|
|
233
|
+
if (index < 0) {
|
|
234
|
+
throw invalidInput(`no task '${args.taskId}' in ${args.tasksYaml}`, {
|
|
235
|
+
action,
|
|
236
|
+
taskId: args.taskId,
|
|
237
|
+
available: resolved.waves.flat().map((t) => t.id),
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
return {
|
|
241
|
+
waveIndex: index,
|
|
242
|
+
wave: resolved.waves[index],
|
|
243
|
+
waves: [resolved.waves[index]],
|
|
244
|
+
blockedByFailure: resolved.blockedByFailure,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
// The waves are the plan's shape; a long plan would dump every task
|
|
248
|
+
// in every wave, so the wave COUNT is reported and the waves
|
|
249
|
+
// themselves are bounded.
|
|
250
|
+
const p = project(resolved.waves, {
|
|
251
|
+
limit: args.limit,
|
|
252
|
+
offset: args.offset,
|
|
253
|
+
next: `archgen_tasks{action:'next',tasksYaml:'${args.tasksYaml}',limit:${args.limit ?? 50},offset:${(args.offset ?? 0) + (args.limit ?? 50)}}`,
|
|
254
|
+
});
|
|
255
|
+
return withMeta(
|
|
256
|
+
{ ...resolved, waves: p.items },
|
|
257
|
+
moreMeta({
|
|
258
|
+
total: p.total,
|
|
259
|
+
returned: p.returned,
|
|
260
|
+
next: p.next,
|
|
261
|
+
available: { waves: p.total, tasks: resolved.waves.flat().length },
|
|
262
|
+
more: `archgen_tasks{action:'next',tasksYaml:'${args.tasksYaml}',taskId:'<one task>'}`,
|
|
263
|
+
}),
|
|
264
|
+
);
|
|
200
265
|
}
|
|
201
266
|
default:
|
|
202
267
|
throw invalidInput(`unknown action '${action}'`, { action });
|