@wrongstack/core 0.300.0 → 0.302.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/chronicle/index.d.ts +2 -0
- package/dist/chronicle/index.js +297 -10
- package/dist/chronicle/project-server.js +253 -15
- package/dist/chronicle/sqlite-compaction.d.ts +20 -0
- package/dist/chronicle/sqlite-journal.d.ts +57 -0
- package/dist/coordination/agents/capability-manifest.d.ts +7 -0
- package/dist/coordination/agents/index.d.ts +3 -2
- package/dist/coordination/agents/index.js +818 -570
- package/dist/coordination/agents/project-agent-identity.d.ts +6 -6
- package/dist/coordination/agents/role-skills.d.ts +1 -1
- package/dist/coordination/agents/types.d.ts +6 -0
- package/dist/coordination/director.d.ts +2 -2
- package/dist/coordination/index.js +6787 -6447
- package/dist/coordination/mail-tools.d.ts +3 -3
- package/dist/coordination/mailbox-project-server.js +3 -4
- package/dist/coordination/mailbox-types.d.ts +6 -0
- package/dist/core/agent-response.d.ts +5 -1
- package/dist/core/agent-tools.d.ts +3 -0
- package/dist/core/context.d.ts +20 -0
- package/dist/core/index.d.ts +8 -7
- package/dist/core/index.js +893 -284
- package/dist/core/instruction-template.d.ts +6 -3
- package/dist/core/next-steps-slot.d.ts +88 -0
- package/dist/core/system-prompt-builder.d.ts +5 -3
- package/dist/core/system-prompt-memory-skills.d.ts +1 -0
- package/dist/core/system-prompt-skill-bodies.d.ts +3 -3
- package/dist/defaults/index.js +9797 -8898
- package/dist/design/index.js +11 -3
- package/dist/execution/auto-compaction-middleware.d.ts +17 -0
- package/dist/execution/autonomy-brain.d.ts +8 -2
- package/dist/execution/brain-runtime.d.ts +3 -1
- package/dist/execution/compaction-core.d.ts +41 -2
- package/dist/execution/council-brain.d.ts +37 -2
- package/dist/execution/council-orchestrator.d.ts +2 -2
- package/dist/execution/index.d.ts +11 -10
- package/dist/execution/index.js +5179 -4078
- package/dist/execution/tool-executor.d.ts +4 -1
- package/dist/execution/topic-shift-advisor.d.ts +53 -0
- package/dist/extension/index.js +8 -2
- package/dist/extension/registry.d.ts +8 -1
- package/dist/goal/index.js +11 -3
- package/dist/hooks/index.js +42 -9
- package/dist/hooks/runner.d.ts +12 -1
- package/dist/hq/index.js +41 -17
- package/dist/hq/publisher.d.ts +21 -3
- package/dist/index.d.ts +21 -20
- package/dist/index.js +10901 -8067
- package/dist/infrastructure/index.js +108 -21
- package/dist/kernel/events/session-events.d.ts +13 -0
- package/dist/kernel/events/tool-events.d.ts +3 -3
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.js +17 -0
- package/dist/models/provider-credentials.d.ts +54 -0
- package/dist/plugin/index.d.ts +1 -0
- package/dist/plugin/index.js +2024 -502
- package/dist/plugins/auto-review-plugin.d.ts +3 -0
- package/dist/plugins/cloud-config-sync-plugin.d.ts +22 -0
- package/dist/plugins/review-claim-registry.d.ts +23 -8
- package/dist/plugins/review-types.d.ts +2 -0
- package/dist/registry/index.js +109 -74
- package/dist/registry/tool-registry.d.ts +15 -0
- package/dist/security/capabilities.d.ts +2 -0
- package/dist/security/index.d.ts +1 -1
- package/dist/security/index.js +9 -2
- package/dist/security/readonly-permission-policy.d.ts +20 -0
- package/dist/session-registry-atomic-file.d.ts +32 -5
- package/dist/session-registry-types.d.ts +17 -0
- package/dist/session-registry.d.ts +1 -1
- package/dist/skills/frontmatter.d.ts +6 -0
- package/dist/skills/index.js +22 -5
- package/dist/storage/cloud-config-sync/sanitize.d.ts +54 -0
- package/dist/storage/cloud-config-sync.d.ts +87 -0
- package/dist/storage/index.d.ts +2 -1
- package/dist/storage/index.js +854 -66
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.js +511 -234
- package/dist/tools/one-shot-llm-tool.d.ts +1 -0
- package/dist/tools/plugin-manager.d.ts +27 -0
- package/dist/types/config/mcp-features.d.ts +18 -11
- package/dist/types/config/root.d.ts +8 -1
- package/dist/types/config/runtime.d.ts +20 -6
- package/dist/types/config/skills-fleet-brain.d.ts +12 -4
- package/dist/types/config/tools.d.ts +16 -0
- package/dist/types/context-window.d.ts +1 -0
- package/dist/types/hooks.d.ts +14 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.js +1 -0
- package/dist/types/multi-agent.d.ts +2 -0
- package/dist/types/one-shot-llm.d.ts +16 -0
- package/dist/types/provider.d.ts +16 -0
- package/dist/types/runtime-capability-manifest.d.ts +168 -0
- package/dist/types/skill.d.ts +5 -0
- package/dist/types/system-prompt.d.ts +3 -1
- package/dist/types/tool-executor.d.ts +8 -1
- package/dist/utils/context-breakdown.d.ts +8 -2
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +141 -31
- package/dist/utils/regex-guard.d.ts +16 -2
- package/dist/utils/sage-output-block.d.ts +7 -10
- package/dist/utils/wstack-paths.d.ts +11 -3
- package/instructions/agents/browser.md +1 -4
- package/instructions/agents/e2e.md +17 -15
- package/instructions/agents/ios.md +3 -3
- package/instructions/agents/search.md +1 -1
- package/instructions/autonomy/goal-preamble.md +4 -4
- package/instructions/coordination/director-preamble.md +2 -3
- package/instructions/coordination/subagent-baseline.md +3 -1
- package/instructions/leader-after-task.md +12 -0
- package/instructions/llm/chimera-review.md +1 -1
- package/instructions/modes/audit-lite.md +1 -1
- package/instructions/sections/tool/common-patterns.md +18 -2
- package/instructions/sections/tool/mailbox-compact.md +1 -1
- package/instructions/sections/tool/mailbox-full.md +1 -1
- package/instructions/system-lite.md +10 -0
- package/instructions/system-pro.md +23 -14
- package/instructions/system.md +22 -13
- package/package.json +3 -3
- package/skills/api-design/SKILL.md +3 -0
- package/skills/audit-log/SKILL.md +2 -0
- package/skills/auto-review/SKILL.md +6 -1
- package/skills/bug-hunter/SKILL.md +4 -1
- package/skills/chimera/SKILL.md +3 -0
- package/skills/data-governance/SKILL.md +3 -0
- package/skills/design-system/SKILL.md +5 -2
- package/skills/docker-deploy/SKILL.md +2 -0
- package/skills/git-flow/SKILL.md +2 -0
- package/skills/mailbox-bridge/SKILL.md +3 -0
- package/skills/mnemosyne/SKILL.md +2 -0
- package/skills/multi-agent/SKILL.md +4 -1
- package/skills/node-modern/SKILL.md +4 -1
- package/skills/observability/SKILL.md +3 -0
- package/skills/output-standards/SKILL.md +2 -0
- package/skills/plugin-author/SKILL.md +4 -1
- package/skills/prompt-engineering/SKILL.md +3 -1
- package/skills/react-modern/SKILL.md +6 -3
- package/skills/refactor-planner/SKILL.md +2 -0
- package/skills/research-web/SKILL.md +3 -0
- package/skills/sdd/SKILL.md +3 -1
- package/skills/security-scanner/SKILL.md +3 -0
- package/skills/skill-creator/SKILL.md +2 -0
- package/skills/tech-stack/SKILL.md +3 -0
- package/skills/testing/SKILL.md +4 -1
- package/skills/typescript-strict/SKILL.md +4 -1
- package/skills/wrongstack-kanban/SKILL.md +6 -3
- package/skills/wrongstack-mailbox/SKILL.md +4 -1
- package/skills/wrongstack-mailbox-mcp/SKILL.md +10 -8
|
@@ -1,56 +1,3 @@
|
|
|
1
|
-
// src/coordination/agents/types.ts
|
|
2
|
-
var HOUR = 60 * 60 * 1e3;
|
|
3
|
-
var LIGHT_BUDGET = {
|
|
4
|
-
timeoutMs: 3 * HOUR,
|
|
5
|
-
maxIterations: 3e3,
|
|
6
|
-
maxToolCalls: 8e3
|
|
7
|
-
};
|
|
8
|
-
var MEDIUM_BUDGET = {
|
|
9
|
-
timeoutMs: 5 * HOUR,
|
|
10
|
-
maxIterations: 5e3,
|
|
11
|
-
maxToolCalls: 14e3
|
|
12
|
-
};
|
|
13
|
-
var HEAVY_BUDGET = {
|
|
14
|
-
timeoutMs: 10 * HOUR,
|
|
15
|
-
maxIterations: 8e3,
|
|
16
|
-
maxToolCalls: 2e4
|
|
17
|
-
};
|
|
18
|
-
var TOOLS = {
|
|
19
|
-
/** Pure read/inspect — safe for analysis and review agents. */
|
|
20
|
-
read: ["read", "grep", "glob", "search", "tree", "mailbox"],
|
|
21
|
-
/** Read + structured inspection (logs, diffs, json, dependency audit). */
|
|
22
|
-
inspect: ["read", "grep", "glob", "search", "tree", "json", "diff", "logs", "audit", "mailbox"],
|
|
23
|
-
/** Read + edit (no shell). For agents that write code/docs but don't run it. */
|
|
24
|
-
write: ["read", "grep", "glob", "search", "tree", "write", "edit", "replace", "patch", "mailbox"],
|
|
25
|
-
/** Full build loop: edit + run (lint/format/typecheck/test/bash). */
|
|
26
|
-
build: [
|
|
27
|
-
"read",
|
|
28
|
-
"grep",
|
|
29
|
-
"glob",
|
|
30
|
-
"search",
|
|
31
|
-
"tree",
|
|
32
|
-
"write",
|
|
33
|
-
"edit",
|
|
34
|
-
"replace",
|
|
35
|
-
"patch",
|
|
36
|
-
"bash",
|
|
37
|
-
"exec",
|
|
38
|
-
"lint",
|
|
39
|
-
"format",
|
|
40
|
-
"typecheck",
|
|
41
|
-
"test",
|
|
42
|
-
"mailbox"
|
|
43
|
-
],
|
|
44
|
-
/** Version control. */
|
|
45
|
-
vcs: ["read", "grep", "glob", "git", "diff"],
|
|
46
|
-
/** Dependency management + CVE audit. */
|
|
47
|
-
deps: ["read", "grep", "glob", "install", "outdated", "audit", "json", "mailbox"],
|
|
48
|
-
/** Documentation authoring. */
|
|
49
|
-
docs: ["read", "grep", "glob", "search", "tree", "write", "edit", "document", "mailbox"],
|
|
50
|
-
/** Web research. */
|
|
51
|
-
research: ["read", "grep", "glob", "search", "fetch", "mailbox"]
|
|
52
|
-
};
|
|
53
|
-
|
|
54
1
|
// src/coordination/agents/agent-prompts.ts
|
|
55
2
|
import { readFileSync as readFileSync7, statSync as statSync2 } from "node:fs";
|
|
56
3
|
import * as path8 from "node:path";
|
|
@@ -73,6 +20,9 @@ function canonicalProjectRoot(absRoot) {
|
|
|
73
20
|
const commonDirFile = path.join(gitDir, "commondir");
|
|
74
21
|
if (!fs.statSync(commonDirFile).isFile()) return checkoutRoot;
|
|
75
22
|
const commonDir = path.resolve(gitDir, fs.readFileSync(commonDirFile, "utf8").trim());
|
|
23
|
+
const worktreesDir = path.dirname(gitDir);
|
|
24
|
+
if (path.basename(worktreesDir).toLowerCase() !== "worktrees") return checkoutRoot;
|
|
25
|
+
if (path.resolve(worktreesDir, "..") !== commonDir) return checkoutRoot;
|
|
76
26
|
if (path.basename(commonDir).toLowerCase() !== ".git") return checkoutRoot;
|
|
77
27
|
return path.dirname(commonDir);
|
|
78
28
|
} catch {
|
|
@@ -95,7 +45,7 @@ function safeProfileName(name) {
|
|
|
95
45
|
const safe = (name ?? "").replace(/[/\\:]/g, "_").replace(/\.\./g, "_").trim();
|
|
96
46
|
return safe || "default";
|
|
97
47
|
}
|
|
98
|
-
function
|
|
48
|
+
function bootstrapProfileName(globalRoot) {
|
|
99
49
|
try {
|
|
100
50
|
const parsed = JSON.parse(fs.readFileSync(path.join(globalRoot, "config.json"), "utf8"));
|
|
101
51
|
return safeProfileName(
|
|
@@ -113,7 +63,7 @@ function wstackGlobalRoot() {
|
|
|
113
63
|
function resolveWstackPaths(opts) {
|
|
114
64
|
const globalRoot = opts.globalRoot ?? (opts.userHome ? path.join(opts.userHome, ".wrongstack") : wstackGlobalRoot());
|
|
115
65
|
const homeDir = opts.userHome ?? os.homedir();
|
|
116
|
-
const profileName = safeProfileName(opts.profileName ??
|
|
66
|
+
const profileName = safeProfileName(opts.profileName ?? bootstrapProfileName(globalRoot));
|
|
117
67
|
const profileDir = path.join(globalRoot, "profiles", profileName);
|
|
118
68
|
const hash = projectHash(opts.projectRoot);
|
|
119
69
|
const slug = projectSlug(opts.projectRoot);
|
|
@@ -183,7 +133,12 @@ function resolveWstackPaths(opts) {
|
|
|
183
133
|
projectRequirementIntakes: path.join(projectDir, "requirement-intakes"),
|
|
184
134
|
syncConfig: path.join(profileDir, "sync.json"),
|
|
185
135
|
configHistoryDir: path.join(globalRoot, "config-history"),
|
|
186
|
-
projectStatus: (
|
|
136
|
+
projectStatus: (statusProjectSlug) => {
|
|
137
|
+
if (!/^[a-z0-9](?:[a-z0-9-]{0,39})-[a-f0-9]{6}$/.test(statusProjectSlug)) {
|
|
138
|
+
throw new Error(`Invalid project slug: ${statusProjectSlug}`);
|
|
139
|
+
}
|
|
140
|
+
return path.join(globalRoot, "projects", statusProjectSlug, "status.json");
|
|
141
|
+
}
|
|
187
142
|
};
|
|
188
143
|
}
|
|
189
144
|
|
|
@@ -228,6 +183,8 @@ var ToolCapabilities = {
|
|
|
228
183
|
NET_OUTBOUND: "net.outbound",
|
|
229
184
|
/** Can mutate in-memory session todos only. */
|
|
230
185
|
SESSION_TODO: "session.todo",
|
|
186
|
+
/** Can park after-task `<nextsteps>` suggestions for the current turn. */
|
|
187
|
+
SESSION_NEXTSTEPS: "session.nextsteps",
|
|
231
188
|
/** Can mutate in-memory session mode only. */
|
|
232
189
|
SESSION_MODE: "session.mode",
|
|
233
190
|
/** Can inspect registered tool metadata. */
|
|
@@ -298,6 +255,294 @@ function clampSubagentCapabilities(requested, ceiling = WIDE_SUBAGENT_CAPABILITI
|
|
|
298
255
|
};
|
|
299
256
|
}
|
|
300
257
|
|
|
258
|
+
// src/types/runtime-capability-manifest.ts
|
|
259
|
+
var PLAYWRIGHT_ALIASES = {
|
|
260
|
+
playwright_navigate: "browser_navigate",
|
|
261
|
+
playwright_screenshot: "browser_screenshot",
|
|
262
|
+
playwright_click: "browser_click",
|
|
263
|
+
playwright_type: "browser_type",
|
|
264
|
+
playwright_evaluate: "browser_evaluate",
|
|
265
|
+
playwright_select_option: "browser_select",
|
|
266
|
+
playwright_hover: "browser_hover",
|
|
267
|
+
playwright_fill_form: "browser_type",
|
|
268
|
+
playwright_wait_for: "browser_wait",
|
|
269
|
+
playwright_press_key: "browser_press",
|
|
270
|
+
playwright_drag: "browser_drag"
|
|
271
|
+
};
|
|
272
|
+
var RUNTIME_CAPABILITY_MANIFEST = [
|
|
273
|
+
{
|
|
274
|
+
id: "filesystem.read",
|
|
275
|
+
pack: "core",
|
|
276
|
+
exposure: "direct",
|
|
277
|
+
tools: ["read", "grep", "glob", "tree"]
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
id: "code.inspect",
|
|
281
|
+
pack: "core",
|
|
282
|
+
exposure: "direct",
|
|
283
|
+
tools: [
|
|
284
|
+
"codebase-stats",
|
|
285
|
+
"codebase-search",
|
|
286
|
+
"codebase-incoming-calls",
|
|
287
|
+
"codebase-outgoing-calls",
|
|
288
|
+
"codebase-index",
|
|
289
|
+
"dead-code-scan",
|
|
290
|
+
"diff",
|
|
291
|
+
"json",
|
|
292
|
+
"logs"
|
|
293
|
+
]
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
id: "filesystem.write",
|
|
297
|
+
pack: "development",
|
|
298
|
+
exposure: "direct",
|
|
299
|
+
tools: ["write", "edit", "replace", "patch"]
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
id: "execution.shell",
|
|
303
|
+
pack: "development",
|
|
304
|
+
exposure: "direct",
|
|
305
|
+
tools: ["bash", "exec", "language", "language_info", "language_package"]
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
id: "verification.run",
|
|
309
|
+
pack: "development",
|
|
310
|
+
exposure: "direct",
|
|
311
|
+
tools: ["lint", "format", "typecheck", "test", "e2e_plan"]
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
id: "version-control.manage",
|
|
315
|
+
pack: "development",
|
|
316
|
+
exposure: "direct",
|
|
317
|
+
tools: ["git"]
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
id: "dependencies.manage",
|
|
321
|
+
pack: "development",
|
|
322
|
+
exposure: "on-demand",
|
|
323
|
+
tools: ["install", "outdated", "audit"]
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
id: "documentation.author",
|
|
327
|
+
pack: "development",
|
|
328
|
+
exposure: "on-demand",
|
|
329
|
+
tools: ["document", "design", "scaffold"]
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
id: "web.research",
|
|
333
|
+
pack: "core",
|
|
334
|
+
exposure: "direct",
|
|
335
|
+
tools: ["search", "fetch"]
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
id: "work.plan",
|
|
339
|
+
pack: "core",
|
|
340
|
+
exposure: "direct",
|
|
341
|
+
tools: ["todo", "plan", "task", "kanban", "nextsteps"]
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
id: "coordination.mailbox",
|
|
345
|
+
pack: "fleet",
|
|
346
|
+
exposure: "direct",
|
|
347
|
+
tools: ["mailbox", "mail_send", "mail_inbox", "fleet_status"]
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
id: "fleet.delegate",
|
|
351
|
+
pack: "fleet",
|
|
352
|
+
exposure: "on-demand",
|
|
353
|
+
tools: [
|
|
354
|
+
"delegate",
|
|
355
|
+
"spawn_subagent",
|
|
356
|
+
"assign_task",
|
|
357
|
+
"kanban_queue",
|
|
358
|
+
"await_tasks",
|
|
359
|
+
"ask_subagent",
|
|
360
|
+
"ask_result",
|
|
361
|
+
"roll_up",
|
|
362
|
+
"quality_gate",
|
|
363
|
+
"terminate_subagent",
|
|
364
|
+
"terminate_all",
|
|
365
|
+
"work_complete",
|
|
366
|
+
"collab_debug",
|
|
367
|
+
"fleet_emit",
|
|
368
|
+
"fleet"
|
|
369
|
+
]
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
id: "reasoning.oneshot",
|
|
373
|
+
pack: "core",
|
|
374
|
+
exposure: "on-demand",
|
|
375
|
+
tools: ["llm", "council"]
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
id: "memory.manage",
|
|
379
|
+
pack: "memory",
|
|
380
|
+
exposure: "on-demand",
|
|
381
|
+
tools: ["remember", "search_memory", "find_related_memories", "forget"]
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
id: "memory.curate",
|
|
385
|
+
pack: "memory",
|
|
386
|
+
exposure: "on-demand",
|
|
387
|
+
tools: [
|
|
388
|
+
"memory_candidates",
|
|
389
|
+
"memory_update",
|
|
390
|
+
"memory_delete",
|
|
391
|
+
"memory_recover",
|
|
392
|
+
"memory_backfill_recoverable",
|
|
393
|
+
"memory_for_file",
|
|
394
|
+
"memory_for_path",
|
|
395
|
+
"memory_search",
|
|
396
|
+
"memory_graph",
|
|
397
|
+
"memory_gather_batch",
|
|
398
|
+
"memory_verify",
|
|
399
|
+
"memory_hygiene"
|
|
400
|
+
]
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
id: "browser.interact",
|
|
404
|
+
pack: "browser",
|
|
405
|
+
exposure: "on-demand",
|
|
406
|
+
tools: [
|
|
407
|
+
"browser_open",
|
|
408
|
+
"browser_status",
|
|
409
|
+
"browser_list",
|
|
410
|
+
"browser_navigate",
|
|
411
|
+
"browser_snapshot",
|
|
412
|
+
"browser_screenshot",
|
|
413
|
+
"browser_click",
|
|
414
|
+
"browser_type",
|
|
415
|
+
"browser_select",
|
|
416
|
+
"browser_press",
|
|
417
|
+
"browser_hover",
|
|
418
|
+
"browser_drag",
|
|
419
|
+
"browser_wait",
|
|
420
|
+
"browser_evaluate",
|
|
421
|
+
"browser_upload",
|
|
422
|
+
"browser_close"
|
|
423
|
+
],
|
|
424
|
+
aliases: PLAYWRIGHT_ALIASES
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
id: "mcp.dynamic",
|
|
428
|
+
pack: "mcp",
|
|
429
|
+
exposure: "on-demand",
|
|
430
|
+
tools: ["mcp_use"]
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
id: "automation.manage",
|
|
434
|
+
pack: "admin",
|
|
435
|
+
exposure: "on-demand",
|
|
436
|
+
tools: ["cron_schedule", "cron_list", "cron_cancel", "watch_start", "watch_list", "watch_stop"]
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
id: "context.pin",
|
|
440
|
+
pack: "admin",
|
|
441
|
+
exposure: "on-demand",
|
|
442
|
+
tools: ["pin_add", "pin_list", "pin_remove"]
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
id: "quality.analyze",
|
|
446
|
+
pack: "development",
|
|
447
|
+
exposure: "on-demand",
|
|
448
|
+
tools: ["dead_code_scan", "detect_duplicate_code", "secret_scanner_test", "error_lens_history"]
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
id: "release.manage",
|
|
452
|
+
pack: "development",
|
|
453
|
+
exposure: "on-demand",
|
|
454
|
+
tools: ["git_autocommit", "semver_current", "semver_bump", "semver_changelog"]
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
id: "messaging.telegram",
|
|
458
|
+
pack: "fleet",
|
|
459
|
+
exposure: "on-demand",
|
|
460
|
+
tools: ["telegram_send", "telegram_read", "telegram_approve"]
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
id: "tools.discover",
|
|
464
|
+
pack: "admin",
|
|
465
|
+
exposure: "direct",
|
|
466
|
+
tools: ["tool_search", "tool_use", "tool_help", "batch_tool_use"]
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
id: "runtime.admin",
|
|
470
|
+
pack: "admin",
|
|
471
|
+
exposure: "internal",
|
|
472
|
+
tools: ["set_working_dir", "context_manager", "mode", "skill", "mcp_control"]
|
|
473
|
+
}
|
|
474
|
+
];
|
|
475
|
+
var CAPABILITY_BY_ID = new Map(
|
|
476
|
+
RUNTIME_CAPABILITY_MANIFEST.map((definition) => [definition.id, definition])
|
|
477
|
+
);
|
|
478
|
+
var CAPABILITY_BY_TOOL = /* @__PURE__ */ new Map();
|
|
479
|
+
var TOOL_ALIASES = /* @__PURE__ */ new Map();
|
|
480
|
+
for (const definition of RUNTIME_CAPABILITY_MANIFEST) {
|
|
481
|
+
for (const tool of definition.tools) {
|
|
482
|
+
CAPABILITY_BY_TOOL.set(tool, definition.id);
|
|
483
|
+
}
|
|
484
|
+
for (const [alias, tool] of Object.entries(definition.aliases ?? {})) {
|
|
485
|
+
TOOL_ALIASES.set(alias, tool);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
function toolsForRuntimeCapabilities(capabilityIds) {
|
|
489
|
+
return [
|
|
490
|
+
...new Set(
|
|
491
|
+
capabilityIds.flatMap((id) => {
|
|
492
|
+
const definition = CAPABILITY_BY_ID.get(id);
|
|
493
|
+
if (!definition) throw new Error(`Unknown runtime capability: "${id}"`);
|
|
494
|
+
return definition.tools;
|
|
495
|
+
})
|
|
496
|
+
)
|
|
497
|
+
];
|
|
498
|
+
}
|
|
499
|
+
function normalizeRuntimeToolName(name) {
|
|
500
|
+
return TOOL_ALIASES.get(name) ?? name;
|
|
501
|
+
}
|
|
502
|
+
function runtimeCapabilityForTool(name) {
|
|
503
|
+
return CAPABILITY_BY_TOOL.get(normalizeRuntimeToolName(name));
|
|
504
|
+
}
|
|
505
|
+
function isKnownRuntimeCapability(id) {
|
|
506
|
+
return CAPABILITY_BY_ID.has(id);
|
|
507
|
+
}
|
|
508
|
+
function inferRuntimeCapabilities(toolNames) {
|
|
509
|
+
const ids = /* @__PURE__ */ new Set();
|
|
510
|
+
for (const rawName of toolNames) {
|
|
511
|
+
const id = runtimeCapabilityForTool(rawName);
|
|
512
|
+
if (id) ids.add(id);
|
|
513
|
+
}
|
|
514
|
+
return [...ids];
|
|
515
|
+
}
|
|
516
|
+
function missingRuntimeCapabilities(required, toolNames) {
|
|
517
|
+
if (!required || required.length === 0) return [];
|
|
518
|
+
const available = new Set(inferRuntimeCapabilities(toolNames));
|
|
519
|
+
return required.filter((id) => !CAPABILITY_BY_ID.has(id) || !available.has(id));
|
|
520
|
+
}
|
|
521
|
+
function missingRequiredRuntimeTools(required, toolNames) {
|
|
522
|
+
if (!required || required.length === 0) return [];
|
|
523
|
+
const available = new Set(toolNames.map(normalizeRuntimeToolName));
|
|
524
|
+
return required.map(normalizeRuntimeToolName).filter((name) => !CAPABILITY_BY_TOOL.has(name) || !available.has(name));
|
|
525
|
+
}
|
|
526
|
+
function runtimeToolReferencesFromText(text) {
|
|
527
|
+
const references = /* @__PURE__ */ new Set();
|
|
528
|
+
for (const match of text.matchAll(/`([a-z][a-z0-9_-]+)`/gi)) {
|
|
529
|
+
const name = normalizeRuntimeToolName(match[1] ?? "");
|
|
530
|
+
if (CAPABILITY_BY_TOOL.has(name)) references.add(name);
|
|
531
|
+
}
|
|
532
|
+
for (const pattern of [
|
|
533
|
+
/\b(?:call|use|invoke|run)\s+`([a-z][a-z0-9_-]+)`/gi,
|
|
534
|
+
/`([a-z][a-z0-9_-]+)`\s+tool\b/gi
|
|
535
|
+
]) {
|
|
536
|
+
for (const match of text.matchAll(pattern)) {
|
|
537
|
+
references.add(normalizeRuntimeToolName(match[1] ?? ""));
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return [...references];
|
|
541
|
+
}
|
|
542
|
+
function isDeprecatedRuntimeToolAlias(name) {
|
|
543
|
+
return TOOL_ALIASES.has(name) || name.startsWith("mcp__");
|
|
544
|
+
}
|
|
545
|
+
|
|
301
546
|
// src/coordination/agents/project-agent-config-validation.ts
|
|
302
547
|
import * as path2 from "node:path";
|
|
303
548
|
var PROJECT_AGENT_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -437,73 +682,28 @@ function validateProjectAgentAvailability(value) {
|
|
|
437
682
|
}
|
|
438
683
|
}
|
|
439
684
|
|
|
440
|
-
// src/coordination/agents/project-agent-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
kotlin: {
|
|
449
|
-
registry: "https://registry.npmjs.org/kotlin/latest",
|
|
450
|
-
key: "version",
|
|
451
|
-
description: "Kotlin latest stable"
|
|
452
|
-
}
|
|
453
|
-
},
|
|
454
|
-
checklist: [
|
|
455
|
-
"Current Android Gradle Plugin version (8.x+)",
|
|
456
|
-
"Current Kotlin version (2.x+)",
|
|
457
|
-
"Current compileSdk / targetSdk (\u2265 34, check Play Store policy)",
|
|
458
|
-
"Current Jetpack Compose stable version",
|
|
459
|
-
"All third-party dependencies are at latest compatible minor"
|
|
460
|
-
],
|
|
461
|
-
verifyThreshold: 0.5
|
|
462
|
-
},
|
|
463
|
-
frontend: {
|
|
464
|
-
role: "frontend",
|
|
465
|
-
liveQueries: {
|
|
466
|
-
react: {
|
|
467
|
-
registry: "https://registry.npmjs.org/react/latest",
|
|
468
|
-
key: "version",
|
|
469
|
-
description: "React latest stable"
|
|
470
|
-
},
|
|
471
|
-
nextjs: {
|
|
472
|
-
registry: "https://registry.npmjs.org/next/latest",
|
|
473
|
-
key: "version",
|
|
474
|
-
description: "Next.js latest stable"
|
|
475
|
-
}
|
|
476
|
-
},
|
|
477
|
-
checklist: [
|
|
478
|
-
"Current React version (pinned in package.json)",
|
|
479
|
-
"Current Next.js / Vite / framework version",
|
|
480
|
-
"Node.js runtime version (project .nvmrc or engines)",
|
|
481
|
-
"All devDependencies are at latest compatible versions",
|
|
482
|
-
"Browser compatibility targets from browserslist"
|
|
483
|
-
],
|
|
484
|
-
verifyThreshold: 0.5
|
|
485
|
-
},
|
|
486
|
-
executor: {
|
|
487
|
-
role: "executor",
|
|
488
|
-
liveQueries: {
|
|
489
|
-
node: {
|
|
490
|
-
registry: "https://registry.npmjs.org/node/latest",
|
|
491
|
-
key: "version",
|
|
492
|
-
description: "Node.js latest release"
|
|
493
|
-
}
|
|
494
|
-
},
|
|
495
|
-
checklist: [
|
|
496
|
-
"Node.js version from .nvmrc or package.engines",
|
|
497
|
-
"TypeScript version from package.json",
|
|
498
|
-
"Package manager (pnpm \u2265 9) from packageManager",
|
|
499
|
-
"Current toolchain: esbuild, vitest, etc."
|
|
500
|
-
],
|
|
501
|
-
verifyThreshold: 0.6
|
|
502
|
-
}
|
|
503
|
-
};
|
|
685
|
+
// src/coordination/agents/project-agent-consolidation.ts
|
|
686
|
+
import {
|
|
687
|
+
existsSync,
|
|
688
|
+
mkdirSync as mkdirSync2,
|
|
689
|
+
readFileSync as readFileSync2,
|
|
690
|
+
rmSync as rmSync2
|
|
691
|
+
} from "node:fs";
|
|
692
|
+
import * as path4 from "node:path";
|
|
504
693
|
|
|
505
|
-
// src/coordination/agents/project-agent-learning-
|
|
506
|
-
|
|
694
|
+
// src/coordination/agents/project-agent-learning-entries.ts
|
|
695
|
+
function tokenOverlap(a, b) {
|
|
696
|
+
const setA = new Set(a.split(/\s+/));
|
|
697
|
+
const setB = new Set(b.split(/\s+/));
|
|
698
|
+
const intersect = new Set([...setA].filter((t) => setB.has(t)));
|
|
699
|
+
const union = /* @__PURE__ */ new Set([...setA, ...setB]);
|
|
700
|
+
return union.size === 0 ? 0 : intersect.size / union.size;
|
|
701
|
+
}
|
|
702
|
+
function splitLearnedEntries(body) {
|
|
703
|
+
return body.split(/\n---\n+/).map((entry) => entry.trim()).map(
|
|
704
|
+
(entry) => entry.replace(/^# Learned wisdom for .+$/im, "").replace(/<!--[\s\S]*?-->/g, "").trim()
|
|
705
|
+
).filter(Boolean);
|
|
706
|
+
}
|
|
507
707
|
|
|
508
708
|
// src/coordination/agents/project-agent-paths.ts
|
|
509
709
|
import { randomUUID } from "node:crypto";
|
|
@@ -547,54 +747,199 @@ function projectAgentProfilePath(role, projectRoot) {
|
|
|
547
747
|
return path3.join(roleDir(role, projectRoot), "profile.json");
|
|
548
748
|
}
|
|
549
749
|
|
|
550
|
-
// src/coordination/agents/project-agent-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
function loadProjectAgentLearningPolicy(role, projectRoot) {
|
|
750
|
+
// src/coordination/agents/project-agent-consolidation.ts
|
|
751
|
+
function learnedPath(role, projectRoot) {
|
|
752
|
+
return path4.join(roleDir(role, projectRoot), "learned.md");
|
|
753
|
+
}
|
|
754
|
+
function loadProjectAgentLearnedText(role, projectRoot) {
|
|
556
755
|
try {
|
|
557
|
-
|
|
558
|
-
readFileSync2(learningPolicyPath(role, projectRoot), "utf8")
|
|
559
|
-
);
|
|
560
|
-
return {
|
|
561
|
-
enabled: parsed.enabled !== false,
|
|
562
|
-
lifetimeCaptureCount: typeof parsed.lifetimeCaptureCount === "number" && Number.isInteger(parsed.lifetimeCaptureCount) && parsed.lifetimeCaptureCount >= 0 ? parsed.lifetimeCaptureCount : 0,
|
|
563
|
-
...typeof parsed.lastCaptureAt === "string" ? { lastCaptureAt: parsed.lastCaptureAt } : {},
|
|
564
|
-
...parsed.lastCaptureSource === "automatic" || parsed.lastCaptureSource === "manual" || parsed.lastCaptureSource === "taught" ? { lastCaptureSource: parsed.lastCaptureSource } : {}
|
|
565
|
-
};
|
|
756
|
+
return readFileSync2(learnedPath(role, projectRoot), "utf8").trim();
|
|
566
757
|
} catch {
|
|
567
|
-
return
|
|
758
|
+
return "";
|
|
568
759
|
}
|
|
569
760
|
}
|
|
570
|
-
function
|
|
571
|
-
|
|
572
|
-
const updated = {
|
|
573
|
-
...current,
|
|
574
|
-
...patch.enabled !== void 0 ? { enabled: patch.enabled } : {}
|
|
575
|
-
};
|
|
576
|
-
writeTextAtomically(
|
|
577
|
-
learningPolicyPath(role, projectRoot),
|
|
578
|
-
`${JSON.stringify(updated, null, 2)}
|
|
579
|
-
`
|
|
580
|
-
);
|
|
581
|
-
return updated;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
// src/coordination/agents/project-agent-learning-entries.ts
|
|
585
|
-
function tokenOverlap(a, b) {
|
|
586
|
-
const setA = new Set(a.split(/\s+/));
|
|
587
|
-
const setB = new Set(b.split(/\s+/));
|
|
588
|
-
const intersect = new Set([...setA].filter((t) => setB.has(t)));
|
|
589
|
-
const union = /* @__PURE__ */ new Set([...setA, ...setB]);
|
|
590
|
-
return union.size === 0 ? 0 : intersect.size / union.size;
|
|
761
|
+
function listProjectAgentLearnedTextEntries(role, projectRoot) {
|
|
762
|
+
return splitLearnedEntries(loadProjectAgentLearnedText(role, projectRoot));
|
|
591
763
|
}
|
|
592
|
-
function
|
|
593
|
-
return
|
|
594
|
-
|
|
595
|
-
|
|
764
|
+
function consolidationPath(role, projectRoot) {
|
|
765
|
+
return path4.join(roleDir(role, projectRoot), "consolidated.md");
|
|
766
|
+
}
|
|
767
|
+
function consolidationMetaPath(role, projectRoot) {
|
|
768
|
+
return path4.join(roleDir(role, projectRoot), "consolidation.json");
|
|
769
|
+
}
|
|
770
|
+
function loadProjectAgentConsolidated(role, projectRoot) {
|
|
771
|
+
try {
|
|
772
|
+
return readFileSync2(consolidationPath(role, projectRoot), "utf8").trim();
|
|
773
|
+
} catch {
|
|
774
|
+
return "";
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
function loadConsolidationMetadata(role, projectRoot) {
|
|
778
|
+
try {
|
|
779
|
+
const raw = readFileSync2(consolidationMetaPath(role, projectRoot), "utf8");
|
|
780
|
+
const parsed = JSON.parse(raw);
|
|
781
|
+
if (typeof parsed === "object" && parsed !== null && typeof parsed.consolidatedAt === "string" && typeof parsed.sourceEntryCount === "number") {
|
|
782
|
+
return parsed;
|
|
783
|
+
}
|
|
784
|
+
return void 0;
|
|
785
|
+
} catch {
|
|
786
|
+
return void 0;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
function isConsolidated(role, projectRoot) {
|
|
790
|
+
return existsSync(consolidationMetaPath(role, projectRoot));
|
|
791
|
+
}
|
|
792
|
+
function saveProjectAgentConsolidated(role, content, projectRoot, metadata) {
|
|
793
|
+
if (!content.trim()) {
|
|
794
|
+
return consolidationPath(assertProjectAgentRole(role), projectRoot);
|
|
795
|
+
}
|
|
796
|
+
const normalizedRole = assertProjectAgentRole(role);
|
|
797
|
+
const dir = roleDir(normalizedRole, projectRoot);
|
|
798
|
+
mkdirSync2(dir, { recursive: true });
|
|
799
|
+
const fp = consolidationPath(normalizedRole, projectRoot);
|
|
800
|
+
writeTextAtomically(fp, content);
|
|
801
|
+
const rawEntries = listProjectAgentLearnedTextEntries(normalizedRole, projectRoot);
|
|
802
|
+
const rawBytes = Buffer.byteLength(loadProjectAgentLearnedText(normalizedRole, projectRoot), "utf8");
|
|
803
|
+
const meta = {
|
|
804
|
+
consolidatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
805
|
+
sourceEntryCount: rawEntries.length,
|
|
806
|
+
sourceBytes: rawBytes,
|
|
807
|
+
consolidatedBytes: Buffer.byteLength(content, "utf8"),
|
|
808
|
+
trigger: metadata?.trigger ?? "manual",
|
|
809
|
+
...metadata?.model ? { model: metadata.model } : {}
|
|
810
|
+
};
|
|
811
|
+
writeTextAtomically(
|
|
812
|
+
consolidationMetaPath(normalizedRole, projectRoot),
|
|
813
|
+
`${JSON.stringify(meta, null, 2)}
|
|
814
|
+
`
|
|
815
|
+
);
|
|
816
|
+
return fp;
|
|
817
|
+
}
|
|
818
|
+
function clearProjectAgentConsolidated(role, projectRoot) {
|
|
819
|
+
const normalizedRole = assertProjectAgentRole(role);
|
|
820
|
+
for (const file of [
|
|
821
|
+
consolidationPath(normalizedRole, projectRoot),
|
|
822
|
+
consolidationMetaPath(normalizedRole, projectRoot)
|
|
823
|
+
]) {
|
|
824
|
+
try {
|
|
825
|
+
rmSync2(file, { force: true });
|
|
826
|
+
} catch {
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
function buildConsolidationInstruction(role, projectRoot) {
|
|
831
|
+
const normalizedRole = assertProjectAgentRole(role);
|
|
832
|
+
const rawEntries = listProjectAgentLearnedTextEntries(normalizedRole, projectRoot);
|
|
833
|
+
const existingConsolidation = loadProjectAgentConsolidated(normalizedRole, projectRoot);
|
|
834
|
+
const rawBody = rawEntries.map((entry, i) => `### Entry ${i + 1}
|
|
835
|
+
|
|
836
|
+
${entry}`).join("\n\n");
|
|
837
|
+
const sections = [
|
|
838
|
+
`You are reviewing and consolidating the captured learning entries for the "${normalizedRole}" agent role in this project.`,
|
|
839
|
+
"",
|
|
840
|
+
"Your task is to synthesize the raw entries below into a single, narrowly-scoped document that represents what this agent has learned \u2014 specifically for its skills and role responsibilities. This document is the **instruction manual for future invocations** of this agent in this project. It is not a journal, not an exhaustive transcription, and not a memory store.",
|
|
841
|
+
"",
|
|
842
|
+
"## Requirements",
|
|
843
|
+
"",
|
|
844
|
+
"1. **Be selective.** Some raw entries are noise \u2014 narrative descriptions of single-session events, ephemeral references (commit SHAs, timestamps, line numbers, PR refs), or thin fragments that cannot be generalized. **Drop them.** The output must be smaller than the input; a consolidation that preserves every word is not a consolidation.",
|
|
845
|
+
'2. **Extract the directive.** When a raw entry mixes narrative framing with a buried lesson ("When I worked on X, I realized Y"), extract the lesson as a directive and discard the framing.',
|
|
846
|
+
"3. **Generic, not specific.** Rewrite entries so they apply across sessions. Replace session-specific anchors (commit SHAs, dates, line numbers) with general principles or concrete tools/commands that will still be valid next month.",
|
|
847
|
+
"4. **Self-contained bullets.** Each bullet must make sense standalone \u2014 understandable to a future agent that has no context about the session that produced it.",
|
|
848
|
+
"5. **Narrow scope.** Keep only knowledge that is genuinely durable and role-relevant. When in doubt, leave it out.",
|
|
849
|
+
"6. **Structured format.** Organize the content under clear markdown headings (##) by topic. Use bullet points for individual facts. Group by category (Conventions, Patterns, Warnings, Project Facts) when it helps scannability.",
|
|
850
|
+
"7. **Preserve actionable anchors.** Keep exact file paths, command names, package names, and configuration values that make a directive concrete and runnable.",
|
|
851
|
+
"8. **No filler.** Do not include meta-commentary about the consolidation process. The document should read as if it were always a single authoritative reference.",
|
|
852
|
+
"",
|
|
853
|
+
rawEntries.length > 0 ? `## Raw learned entries (${rawEntries.length} total)
|
|
854
|
+
|
|
855
|
+
${rawBody}` : "## Raw learned entries\n\n(No raw entries yet \u2014 return an empty document.)"
|
|
856
|
+
];
|
|
857
|
+
if (existingConsolidation) {
|
|
858
|
+
sections.push(
|
|
859
|
+
"",
|
|
860
|
+
`## Existing consolidated document (for reference \u2014 improve upon it)
|
|
861
|
+
|
|
862
|
+
${existingConsolidation}`
|
|
863
|
+
);
|
|
864
|
+
}
|
|
865
|
+
sections.push(
|
|
866
|
+
"",
|
|
867
|
+
"## Output",
|
|
868
|
+
"",
|
|
869
|
+
"Return ONLY the consolidated markdown document. Do not wrap it in code fences or add commentary."
|
|
870
|
+
);
|
|
871
|
+
return {
|
|
872
|
+
instruction: sections.join("\n"),
|
|
873
|
+
rawEntries,
|
|
874
|
+
hasExistingConsolidation: Boolean(existingConsolidation)
|
|
875
|
+
};
|
|
596
876
|
}
|
|
597
877
|
|
|
878
|
+
// src/coordination/agents/project-agent-knowledge-manifests.ts
|
|
879
|
+
var BUILT_IN_KNOWLEDGE_MANIFESTS = {
|
|
880
|
+
android: {
|
|
881
|
+
role: "android",
|
|
882
|
+
// Only machine-readable JSON registries belong in liveQueries. Android
|
|
883
|
+
// release/API data has no JSON registry endpoint, so those checks stay as
|
|
884
|
+
// checklist prose below.
|
|
885
|
+
liveQueries: {
|
|
886
|
+
kotlin: {
|
|
887
|
+
registry: "https://registry.npmjs.org/kotlin/latest",
|
|
888
|
+
key: "version",
|
|
889
|
+
description: "Kotlin latest stable"
|
|
890
|
+
}
|
|
891
|
+
},
|
|
892
|
+
checklist: [
|
|
893
|
+
"Current Android Gradle Plugin version (8.x+)",
|
|
894
|
+
"Current Kotlin version (2.x+)",
|
|
895
|
+
"Current compileSdk / targetSdk (\u2265 34, check Play Store policy)",
|
|
896
|
+
"Current Jetpack Compose stable version",
|
|
897
|
+
"All third-party dependencies are at latest compatible minor"
|
|
898
|
+
],
|
|
899
|
+
verifyThreshold: 0.5
|
|
900
|
+
},
|
|
901
|
+
frontend: {
|
|
902
|
+
role: "frontend",
|
|
903
|
+
liveQueries: {
|
|
904
|
+
react: {
|
|
905
|
+
registry: "https://registry.npmjs.org/react/latest",
|
|
906
|
+
key: "version",
|
|
907
|
+
description: "React latest stable"
|
|
908
|
+
},
|
|
909
|
+
nextjs: {
|
|
910
|
+
registry: "https://registry.npmjs.org/next/latest",
|
|
911
|
+
key: "version",
|
|
912
|
+
description: "Next.js latest stable"
|
|
913
|
+
}
|
|
914
|
+
},
|
|
915
|
+
checklist: [
|
|
916
|
+
"Current React version (pinned in package.json)",
|
|
917
|
+
"Current Next.js / Vite / framework version",
|
|
918
|
+
"Node.js runtime version (project .nvmrc or engines)",
|
|
919
|
+
"All devDependencies are at latest compatible versions",
|
|
920
|
+
"Browser compatibility targets from browserslist"
|
|
921
|
+
],
|
|
922
|
+
verifyThreshold: 0.5
|
|
923
|
+
},
|
|
924
|
+
executor: {
|
|
925
|
+
role: "executor",
|
|
926
|
+
liveQueries: {
|
|
927
|
+
node: {
|
|
928
|
+
registry: "https://registry.npmjs.org/node/latest",
|
|
929
|
+
key: "version",
|
|
930
|
+
description: "Node.js latest release"
|
|
931
|
+
}
|
|
932
|
+
},
|
|
933
|
+
checklist: [
|
|
934
|
+
"Node.js version from .nvmrc or package.engines",
|
|
935
|
+
"TypeScript version from package.json",
|
|
936
|
+
"Package manager (pnpm \u2265 9) from packageManager",
|
|
937
|
+
"Current toolchain: esbuild, vitest, etc."
|
|
938
|
+
],
|
|
939
|
+
verifyThreshold: 0.6
|
|
940
|
+
}
|
|
941
|
+
};
|
|
942
|
+
|
|
598
943
|
// src/coordination/agents/project-agent-learning-normalize.ts
|
|
599
944
|
var LEARNED_SOFT_LIMIT = 8192;
|
|
600
945
|
var LEARNED_HARD_LIMIT = 16384;
|
|
@@ -712,6 +1057,41 @@ function normalizeForComparison(text) {
|
|
|
712
1057
|
return text.toLowerCase().replace(/[^\w\s]/g, " ").replace(/\s+/g, " ").trim().split(/\s+/).sort().join(" ");
|
|
713
1058
|
}
|
|
714
1059
|
|
|
1060
|
+
// src/coordination/agents/project-agent-learning-policy.ts
|
|
1061
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
1062
|
+
var DEFAULT_LEARNING_POLICY = {
|
|
1063
|
+
enabled: true,
|
|
1064
|
+
lifetimeCaptureCount: 0
|
|
1065
|
+
};
|
|
1066
|
+
function loadProjectAgentLearningPolicy(role, projectRoot) {
|
|
1067
|
+
try {
|
|
1068
|
+
const parsed = JSON.parse(
|
|
1069
|
+
readFileSync3(learningPolicyPath(role, projectRoot), "utf8")
|
|
1070
|
+
);
|
|
1071
|
+
return {
|
|
1072
|
+
enabled: parsed.enabled !== false,
|
|
1073
|
+
lifetimeCaptureCount: typeof parsed.lifetimeCaptureCount === "number" && Number.isInteger(parsed.lifetimeCaptureCount) && parsed.lifetimeCaptureCount >= 0 ? parsed.lifetimeCaptureCount : 0,
|
|
1074
|
+
...typeof parsed.lastCaptureAt === "string" ? { lastCaptureAt: parsed.lastCaptureAt } : {},
|
|
1075
|
+
...parsed.lastCaptureSource === "automatic" || parsed.lastCaptureSource === "manual" || parsed.lastCaptureSource === "taught" ? { lastCaptureSource: parsed.lastCaptureSource } : {}
|
|
1076
|
+
};
|
|
1077
|
+
} catch {
|
|
1078
|
+
return { ...DEFAULT_LEARNING_POLICY };
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
function updateProjectAgentLearningPolicy(role, patch, projectRoot) {
|
|
1082
|
+
const current = loadProjectAgentLearningPolicy(role, projectRoot);
|
|
1083
|
+
const updated = {
|
|
1084
|
+
...current,
|
|
1085
|
+
...patch.enabled !== void 0 ? { enabled: patch.enabled } : {}
|
|
1086
|
+
};
|
|
1087
|
+
writeTextAtomically(
|
|
1088
|
+
learningPolicyPath(role, projectRoot),
|
|
1089
|
+
`${JSON.stringify(updated, null, 2)}
|
|
1090
|
+
`
|
|
1091
|
+
);
|
|
1092
|
+
return updated;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
715
1095
|
// src/coordination/agents/project-agent-learning-structured.ts
|
|
716
1096
|
function parseLearnedEntryStamp(entry) {
|
|
717
1097
|
const structuredMatch = entry.match(
|
|
@@ -839,311 +1219,86 @@ function mergeStructuredEntries(existing, fresh) {
|
|
|
839
1219
|
};
|
|
840
1220
|
const merged = existing.filter((entry) => tokenOverlap(entry.key, freshEntry.key) < 0.55);
|
|
841
1221
|
merged.push(freshEntry);
|
|
842
|
-
const order = {
|
|
843
|
-
warning: 0,
|
|
844
|
-
convention: 1,
|
|
845
|
-
pattern: 2,
|
|
846
|
-
fact: 3
|
|
847
|
-
};
|
|
848
|
-
merged.sort((a, b) => {
|
|
849
|
-
const cmp = order[a.category] - order[b.category];
|
|
850
|
-
if (cmp !== 0) return cmp;
|
|
851
|
-
return a.what.localeCompare(b.what);
|
|
852
|
-
});
|
|
853
|
-
return merged;
|
|
854
|
-
}
|
|
855
|
-
var SECTION_TITLE = {
|
|
856
|
-
warning: "## What to avoid",
|
|
857
|
-
convention: "## What to do",
|
|
858
|
-
pattern: "## Patterns to follow",
|
|
859
|
-
fact: "## Project facts"
|
|
860
|
-
};
|
|
861
|
-
function renderLearnedInstructions(role, entries, capturedAt) {
|
|
862
|
-
const headerLines = [
|
|
863
|
-
`# Learned instructions for \`${role}\``,
|
|
864
|
-
"",
|
|
865
|
-
"> Project-specific learning data for the `" + role + "` agent. Each entry is a directive \u2014 read it as an instruction, not a journal entry. Entries are re-derived on every capture, so this file is always a current, structured snapshot of what this agent has learned.",
|
|
866
|
-
""
|
|
867
|
-
];
|
|
868
|
-
if (entries.length === 0) {
|
|
869
|
-
return headerLines.join("\n") + [
|
|
870
|
-
"_No learned entries yet._",
|
|
871
|
-
"",
|
|
872
|
-
"---",
|
|
873
|
-
`*Last capture: ${capturedAt} \xB7 0 entries*`,
|
|
874
|
-
""
|
|
875
|
-
].join("\n");
|
|
876
|
-
}
|
|
877
|
-
const buckets = {
|
|
878
|
-
warning: [],
|
|
879
|
-
convention: [],
|
|
880
|
-
pattern: [],
|
|
881
|
-
fact: []
|
|
882
|
-
};
|
|
883
|
-
for (const entry of entries) buckets[entry.category].push(entry);
|
|
884
|
-
const sections = [];
|
|
885
|
-
for (const category of ["warning", "convention", "pattern", "fact"]) {
|
|
886
|
-
const list = buckets[category];
|
|
887
|
-
if (list.length === 0) continue;
|
|
888
|
-
sections.push(SECTION_TITLE[category]);
|
|
889
|
-
sections.push("");
|
|
890
|
-
for (const entry of list) {
|
|
891
|
-
const stamp = `<!-- learned-stamp: category=${entry.category}; capturedAt=${entry.capturedAt} -->`;
|
|
892
|
-
sections.push(stamp);
|
|
893
|
-
sections.push(`- **${entry.what}**`);
|
|
894
|
-
sections.push(` - *Why:* ${entry.why}`);
|
|
895
|
-
if (entry.how) {
|
|
896
|
-
for (const line of entry.how.split("\n"))
|
|
897
|
-
sections.push(` - *How:* ${line.replace(/^- /, "")}`);
|
|
898
|
-
}
|
|
899
|
-
sections.push("");
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
const footer = ["---", `*Last capture: ${capturedAt} \xB7 ${entries.length} entries*`, ""];
|
|
903
|
-
return [...headerLines, ...sections, ...footer].join("\n");
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
// src/coordination/agents/project-agent-consolidation.ts
|
|
907
|
-
import {
|
|
908
|
-
existsSync,
|
|
909
|
-
mkdirSync as mkdirSync2,
|
|
910
|
-
readFileSync as readFileSync3,
|
|
911
|
-
rmSync as rmSync2
|
|
912
|
-
} from "node:fs";
|
|
913
|
-
import * as path4 from "node:path";
|
|
914
|
-
function learnedPath(role, projectRoot) {
|
|
915
|
-
return path4.join(roleDir(role, projectRoot), "learned.md");
|
|
916
|
-
}
|
|
917
|
-
function loadProjectAgentLearnedText(role, projectRoot) {
|
|
918
|
-
try {
|
|
919
|
-
return readFileSync3(learnedPath(role, projectRoot), "utf8").trim();
|
|
920
|
-
} catch {
|
|
921
|
-
return "";
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
function listProjectAgentLearnedTextEntries(role, projectRoot) {
|
|
925
|
-
return splitLearnedEntries(loadProjectAgentLearnedText(role, projectRoot));
|
|
926
|
-
}
|
|
927
|
-
function consolidationPath(role, projectRoot) {
|
|
928
|
-
return path4.join(roleDir(role, projectRoot), "consolidated.md");
|
|
929
|
-
}
|
|
930
|
-
function consolidationMetaPath(role, projectRoot) {
|
|
931
|
-
return path4.join(roleDir(role, projectRoot), "consolidation.json");
|
|
932
|
-
}
|
|
933
|
-
function loadProjectAgentConsolidated(role, projectRoot) {
|
|
934
|
-
try {
|
|
935
|
-
return readFileSync3(consolidationPath(role, projectRoot), "utf8").trim();
|
|
936
|
-
} catch {
|
|
937
|
-
return "";
|
|
938
|
-
}
|
|
939
|
-
}
|
|
940
|
-
function loadConsolidationMetadata(role, projectRoot) {
|
|
941
|
-
try {
|
|
942
|
-
const raw = readFileSync3(consolidationMetaPath(role, projectRoot), "utf8");
|
|
943
|
-
const parsed = JSON.parse(raw);
|
|
944
|
-
if (typeof parsed === "object" && parsed !== null && typeof parsed.consolidatedAt === "string" && typeof parsed.sourceEntryCount === "number") {
|
|
945
|
-
return parsed;
|
|
946
|
-
}
|
|
947
|
-
return void 0;
|
|
948
|
-
} catch {
|
|
949
|
-
return void 0;
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
function isConsolidated(role, projectRoot) {
|
|
953
|
-
return existsSync(consolidationMetaPath(role, projectRoot));
|
|
954
|
-
}
|
|
955
|
-
function saveProjectAgentConsolidated(role, content, projectRoot, metadata) {
|
|
956
|
-
if (!content.trim()) {
|
|
957
|
-
return consolidationPath(assertProjectAgentRole(role), projectRoot);
|
|
958
|
-
}
|
|
959
|
-
const normalizedRole = assertProjectAgentRole(role);
|
|
960
|
-
const dir = roleDir(normalizedRole, projectRoot);
|
|
961
|
-
mkdirSync2(dir, { recursive: true });
|
|
962
|
-
const fp = consolidationPath(normalizedRole, projectRoot);
|
|
963
|
-
writeTextAtomically(fp, content);
|
|
964
|
-
const rawEntries = listProjectAgentLearnedTextEntries(normalizedRole, projectRoot);
|
|
965
|
-
const rawBytes = Buffer.byteLength(loadProjectAgentLearnedText(normalizedRole, projectRoot), "utf8");
|
|
966
|
-
const meta = {
|
|
967
|
-
consolidatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
968
|
-
sourceEntryCount: rawEntries.length,
|
|
969
|
-
sourceBytes: rawBytes,
|
|
970
|
-
consolidatedBytes: Buffer.byteLength(content, "utf8"),
|
|
971
|
-
trigger: metadata?.trigger ?? "manual",
|
|
972
|
-
...metadata?.model ? { model: metadata.model } : {}
|
|
973
|
-
};
|
|
974
|
-
writeTextAtomically(
|
|
975
|
-
consolidationMetaPath(normalizedRole, projectRoot),
|
|
976
|
-
`${JSON.stringify(meta, null, 2)}
|
|
977
|
-
`
|
|
978
|
-
);
|
|
979
|
-
return fp;
|
|
980
|
-
}
|
|
981
|
-
function clearProjectAgentConsolidated(role, projectRoot) {
|
|
982
|
-
const normalizedRole = assertProjectAgentRole(role);
|
|
983
|
-
for (const file of [
|
|
984
|
-
consolidationPath(normalizedRole, projectRoot),
|
|
985
|
-
consolidationMetaPath(normalizedRole, projectRoot)
|
|
986
|
-
]) {
|
|
987
|
-
try {
|
|
988
|
-
rmSync2(file, { force: true });
|
|
989
|
-
} catch {
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
function buildConsolidationInstruction(role, projectRoot) {
|
|
994
|
-
const normalizedRole = assertProjectAgentRole(role);
|
|
995
|
-
const rawEntries = listProjectAgentLearnedTextEntries(normalizedRole, projectRoot);
|
|
996
|
-
const existingConsolidation = loadProjectAgentConsolidated(normalizedRole, projectRoot);
|
|
997
|
-
const rawBody = rawEntries.map((entry, i) => `### Entry ${i + 1}
|
|
998
|
-
|
|
999
|
-
${entry}`).join("\n\n");
|
|
1000
|
-
const sections = [
|
|
1001
|
-
`You are reviewing and consolidating the captured learning entries for the "${normalizedRole}" agent role in this project.`,
|
|
1002
|
-
"",
|
|
1003
|
-
"Your task is to synthesize the raw entries below into a single, narrowly-scoped document that represents what this agent has learned \u2014 specifically for its skills and role responsibilities. This document is the **instruction manual for future invocations** of this agent in this project. It is not a journal, not an exhaustive transcription, and not a memory store.",
|
|
1004
|
-
"",
|
|
1005
|
-
"## Requirements",
|
|
1006
|
-
"",
|
|
1007
|
-
"1. **Be selective.** Some raw entries are noise \u2014 narrative descriptions of single-session events, ephemeral references (commit SHAs, timestamps, line numbers, PR refs), or thin fragments that cannot be generalized. **Drop them.** The output must be smaller than the input; a consolidation that preserves every word is not a consolidation.",
|
|
1008
|
-
'2. **Extract the directive.** When a raw entry mixes narrative framing with a buried lesson ("When I worked on X, I realized Y"), extract the lesson as a directive and discard the framing.',
|
|
1009
|
-
"3. **Generic, not specific.** Rewrite entries so they apply across sessions. Replace session-specific anchors (commit SHAs, dates, line numbers) with general principles or concrete tools/commands that will still be valid next month.",
|
|
1010
|
-
"4. **Self-contained bullets.** Each bullet must make sense standalone \u2014 understandable to a future agent that has no context about the session that produced it.",
|
|
1011
|
-
"5. **Narrow scope.** Keep only knowledge that is genuinely durable and role-relevant. When in doubt, leave it out.",
|
|
1012
|
-
"6. **Structured format.** Organize the content under clear markdown headings (##) by topic. Use bullet points for individual facts. Group by category (Conventions, Patterns, Warnings, Project Facts) when it helps scannability.",
|
|
1013
|
-
"7. **Preserve actionable anchors.** Keep exact file paths, command names, package names, and configuration values that make a directive concrete and runnable.",
|
|
1014
|
-
"8. **No filler.** Do not include meta-commentary about the consolidation process. The document should read as if it were always a single authoritative reference.",
|
|
1015
|
-
"",
|
|
1016
|
-
rawEntries.length > 0 ? `## Raw learned entries (${rawEntries.length} total)
|
|
1017
|
-
|
|
1018
|
-
${rawBody}` : "## Raw learned entries\n\n(No raw entries yet \u2014 return an empty document.)"
|
|
1019
|
-
];
|
|
1020
|
-
if (existingConsolidation) {
|
|
1021
|
-
sections.push(
|
|
1022
|
-
"",
|
|
1023
|
-
`## Existing consolidated document (for reference \u2014 improve upon it)
|
|
1024
|
-
|
|
1025
|
-
${existingConsolidation}`
|
|
1026
|
-
);
|
|
1027
|
-
}
|
|
1028
|
-
sections.push(
|
|
1029
|
-
"",
|
|
1030
|
-
"## Output",
|
|
1031
|
-
"",
|
|
1032
|
-
"Return ONLY the consolidated markdown document. Do not wrap it in code fences or add commentary."
|
|
1033
|
-
);
|
|
1034
|
-
return {
|
|
1035
|
-
instruction: sections.join("\n"),
|
|
1036
|
-
rawEntries,
|
|
1037
|
-
hasExistingConsolidation: Boolean(existingConsolidation)
|
|
1038
|
-
};
|
|
1039
|
-
}
|
|
1040
|
-
|
|
1041
|
-
// src/coordination/agents/project-agent-profile.ts
|
|
1042
|
-
import { existsSync as existsSync2, mkdirSync as mkdirSync3, readdirSync, readFileSync as readFileSync4 } from "node:fs";
|
|
1043
|
-
import * as path5 from "node:path";
|
|
1044
|
-
function slugifyProjectAgentRole(name) {
|
|
1045
|
-
const slug = name.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^[._-]+|[._-]+$/g, "").slice(0, 96);
|
|
1046
|
-
return assertProjectAgentRole(slug);
|
|
1047
|
-
}
|
|
1048
|
-
function loadProjectAgentProfile(role, projectRoot) {
|
|
1049
|
-
try {
|
|
1050
|
-
const parsed = JSON.parse(
|
|
1051
|
-
readFileSync4(projectAgentProfilePath(role, projectRoot), "utf8")
|
|
1052
|
-
);
|
|
1053
|
-
const normalizedRole = assertProjectAgentRole(parsed.role ?? role);
|
|
1054
|
-
const baseRole = assertProjectAgentRole(parsed.baseRole ?? "generic");
|
|
1055
|
-
if (normalizedRole !== assertProjectAgentRole(role)) return void 0;
|
|
1056
|
-
if (typeof parsed.name !== "string" || !parsed.name.trim()) return void 0;
|
|
1057
|
-
if (typeof parsed.purpose !== "string" || !parsed.purpose.trim()) return void 0;
|
|
1058
|
-
if (!Array.isArray(parsed.taskTypes) || parsed.taskTypes.some((item) => typeof item !== "string")) {
|
|
1059
|
-
return void 0;
|
|
1060
|
-
}
|
|
1061
|
-
const createdAt = typeof parsed.createdAt === "string" ? parsed.createdAt : (/* @__PURE__ */ new Date(0)).toISOString();
|
|
1062
|
-
const updatedAt = typeof parsed.updatedAt === "string" ? parsed.updatedAt : createdAt;
|
|
1063
|
-
return {
|
|
1064
|
-
role: normalizedRole,
|
|
1065
|
-
name: parsed.name.trim(),
|
|
1066
|
-
baseRole,
|
|
1067
|
-
purpose: parsed.purpose.trim(),
|
|
1068
|
-
taskTypes: parsed.taskTypes.map((item) => item.trim()).filter(Boolean),
|
|
1069
|
-
createdAt,
|
|
1070
|
-
updatedAt
|
|
1071
|
-
};
|
|
1072
|
-
} catch {
|
|
1073
|
-
return void 0;
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
function createProjectAgent(input, projectRoot) {
|
|
1077
|
-
const name = input.name.trim();
|
|
1078
|
-
const purpose = input.purpose.trim();
|
|
1079
|
-
if (!name || name.length > 120) throw new Error("Project agent name must be 1-120 characters.");
|
|
1080
|
-
if (purpose.length < 10 || purpose.length > 4e3) {
|
|
1081
|
-
throw new Error("Project agent purpose must be 10-4000 characters.");
|
|
1082
|
-
}
|
|
1083
|
-
const role = assertProjectAgentRole(
|
|
1084
|
-
(input.role?.trim() || slugifyProjectAgentRole(name)).toLowerCase()
|
|
1085
|
-
);
|
|
1086
|
-
const baseRole = assertProjectAgentRole((input.baseRole?.trim() || "generic").toLowerCase());
|
|
1087
|
-
const taskTypes = [...new Set(input.taskTypes.map((item) => item.trim()).filter(Boolean))];
|
|
1088
|
-
if (taskTypes.length === 0 || taskTypes.length > 32 || taskTypes.some((item) => item.length > 160)) {
|
|
1089
|
-
throw new Error("Project agent requires 1-32 task descriptions, each at most 160 characters.");
|
|
1090
|
-
}
|
|
1091
|
-
const dir = roleDir(role, projectRoot);
|
|
1092
|
-
if (existsSync2(dir) && readdirSync(dir).length > 0) {
|
|
1093
|
-
throw new Error(`Project agent role "${role}" already exists.`);
|
|
1094
|
-
}
|
|
1095
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1096
|
-
const profile = {
|
|
1097
|
-
role,
|
|
1098
|
-
name,
|
|
1099
|
-
baseRole,
|
|
1100
|
-
purpose,
|
|
1101
|
-
taskTypes,
|
|
1102
|
-
createdAt: now,
|
|
1103
|
-
updatedAt: now
|
|
1104
|
-
};
|
|
1105
|
-
const identity = [
|
|
1106
|
-
`# ${name}`,
|
|
1107
|
-
"",
|
|
1108
|
-
`You are the project-specific "${name}" agent (role: ${role}).`,
|
|
1109
|
-
"",
|
|
1110
|
-
"## Purpose",
|
|
1111
|
-
"",
|
|
1112
|
-
purpose,
|
|
1113
|
-
"",
|
|
1114
|
-
"## Primary task types",
|
|
1115
|
-
"",
|
|
1116
|
-
...taskTypes.map((item) => `- ${item}`),
|
|
1222
|
+
const order = {
|
|
1223
|
+
warning: 0,
|
|
1224
|
+
convention: 1,
|
|
1225
|
+
pattern: 2,
|
|
1226
|
+
fact: 3
|
|
1227
|
+
};
|
|
1228
|
+
merged.sort((a, b) => {
|
|
1229
|
+
const cmp = order[a.category] - order[b.category];
|
|
1230
|
+
if (cmp !== 0) return cmp;
|
|
1231
|
+
return a.what.localeCompare(b.what);
|
|
1232
|
+
});
|
|
1233
|
+
return merged;
|
|
1234
|
+
}
|
|
1235
|
+
var SECTION_TITLE = {
|
|
1236
|
+
warning: "## What to avoid",
|
|
1237
|
+
convention: "## What to do",
|
|
1238
|
+
pattern: "## Patterns to follow",
|
|
1239
|
+
fact: "## Project facts"
|
|
1240
|
+
};
|
|
1241
|
+
function renderLearnedInstructions(role, entries, capturedAt) {
|
|
1242
|
+
const headerLines = [
|
|
1243
|
+
`# Learned instructions for \`${role}\``,
|
|
1117
1244
|
"",
|
|
1118
|
-
"
|
|
1245
|
+
"> Project-specific learning data for the `" + role + "` agent. Each entry is a directive \u2014 read it as an instruction, not a journal entry. Entries are re-derived on every capture, so this file is always a current, structured snapshot of what this agent has learned.",
|
|
1119
1246
|
""
|
|
1120
|
-
]
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1247
|
+
];
|
|
1248
|
+
if (entries.length === 0) {
|
|
1249
|
+
return headerLines.join("\n") + [
|
|
1250
|
+
"_No learned entries yet._",
|
|
1251
|
+
"",
|
|
1252
|
+
"---",
|
|
1253
|
+
`*Last capture: ${capturedAt} \xB7 0 entries*`,
|
|
1254
|
+
""
|
|
1255
|
+
].join("\n");
|
|
1256
|
+
}
|
|
1257
|
+
const buckets = {
|
|
1258
|
+
warning: [],
|
|
1259
|
+
convention: [],
|
|
1260
|
+
pattern: [],
|
|
1261
|
+
fact: []
|
|
1262
|
+
};
|
|
1263
|
+
for (const entry of entries) buckets[entry.category].push(entry);
|
|
1264
|
+
const sections = [];
|
|
1265
|
+
for (const category of ["warning", "convention", "pattern", "fact"]) {
|
|
1266
|
+
const list = buckets[category];
|
|
1267
|
+
if (list.length === 0) continue;
|
|
1268
|
+
sections.push(SECTION_TITLE[category]);
|
|
1269
|
+
sections.push("");
|
|
1270
|
+
for (const entry of list) {
|
|
1271
|
+
const stamp = `<!-- learned-stamp: category=${entry.category}; capturedAt=${entry.capturedAt} -->`;
|
|
1272
|
+
sections.push(stamp);
|
|
1273
|
+
sections.push(`- **${entry.what}**`);
|
|
1274
|
+
sections.push(` - *Why:* ${entry.why}`);
|
|
1275
|
+
if (entry.how) {
|
|
1276
|
+
for (const line of entry.how.split("\n"))
|
|
1277
|
+
sections.push(` - *How:* ${line.replace(/^- /, "")}`);
|
|
1278
|
+
}
|
|
1279
|
+
sections.push("");
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
const footer = ["---", `*Last capture: ${capturedAt} \xB7 ${entries.length} entries*`, ""];
|
|
1283
|
+
return [...headerLines, ...sections, ...footer].join("\n");
|
|
1129
1284
|
}
|
|
1130
1285
|
|
|
1131
1286
|
// src/coordination/agents/project-agent-files.ts
|
|
1132
1287
|
import {
|
|
1133
|
-
existsSync as
|
|
1134
|
-
mkdirSync as
|
|
1135
|
-
readdirSync
|
|
1136
|
-
readFileSync as
|
|
1288
|
+
existsSync as existsSync2,
|
|
1289
|
+
mkdirSync as mkdirSync3,
|
|
1290
|
+
readdirSync,
|
|
1291
|
+
readFileSync as readFileSync4,
|
|
1137
1292
|
rmSync as rmSync3
|
|
1138
1293
|
} from "node:fs";
|
|
1139
|
-
import * as
|
|
1294
|
+
import * as path5 from "node:path";
|
|
1140
1295
|
function updateProjectAgentLearned(role, content, projectRoot, mode = "append") {
|
|
1141
1296
|
const dir = roleDir(role, projectRoot);
|
|
1142
|
-
|
|
1143
|
-
const filePath =
|
|
1297
|
+
mkdirSync3(dir, { recursive: true });
|
|
1298
|
+
const filePath = path5.join(dir, "learned.md");
|
|
1144
1299
|
const existing = (() => {
|
|
1145
1300
|
try {
|
|
1146
|
-
return
|
|
1301
|
+
return readFileSync4(filePath, "utf8");
|
|
1147
1302
|
} catch {
|
|
1148
1303
|
return "";
|
|
1149
1304
|
}
|
|
@@ -1158,24 +1313,24 @@ ${content.trimStart()}` : content;
|
|
|
1158
1313
|
}
|
|
1159
1314
|
function updateProjectAgentIdentity(role, content, projectRoot) {
|
|
1160
1315
|
const dir = roleDir(role, projectRoot);
|
|
1161
|
-
|
|
1162
|
-
const filePath =
|
|
1316
|
+
mkdirSync3(dir, { recursive: true });
|
|
1317
|
+
const filePath = path5.join(dir, "identity.md");
|
|
1163
1318
|
writeTextAtomically(filePath, content);
|
|
1164
1319
|
return filePath;
|
|
1165
1320
|
}
|
|
1166
1321
|
function updateProjectAgentConfig(role, config, projectRoot) {
|
|
1167
1322
|
const validated = validateProjectAgentConfig(config);
|
|
1168
1323
|
const dir = roleDir(role, projectRoot);
|
|
1169
|
-
|
|
1170
|
-
const filePath =
|
|
1324
|
+
mkdirSync3(dir, { recursive: true });
|
|
1325
|
+
const filePath = path5.join(dir, "config.json");
|
|
1171
1326
|
writeTextAtomically(filePath, `${JSON.stringify(validated, null, 2)}
|
|
1172
1327
|
`);
|
|
1173
1328
|
return filePath;
|
|
1174
1329
|
}
|
|
1175
1330
|
function updateProjectAgentKnowledge(role, manifest, projectRoot) {
|
|
1176
1331
|
const dir = roleDir(role, projectRoot);
|
|
1177
|
-
|
|
1178
|
-
const filePath =
|
|
1332
|
+
mkdirSync3(dir, { recursive: true });
|
|
1333
|
+
const filePath = path5.join(dir, "knowledge.json");
|
|
1179
1334
|
writeTextAtomically(filePath, `${JSON.stringify(manifest, null, 2)}
|
|
1180
1335
|
`);
|
|
1181
1336
|
return filePath;
|
|
@@ -1184,14 +1339,14 @@ function resetProjectAgentIdentity(role, projectRoot) {
|
|
|
1184
1339
|
const removed = [];
|
|
1185
1340
|
if (!role || role === "*") {
|
|
1186
1341
|
const dir2 = agentsDir(projectRoot);
|
|
1187
|
-
if (
|
|
1342
|
+
if (existsSync2(dir2)) {
|
|
1188
1343
|
rmSync3(dir2, { recursive: true, force: true });
|
|
1189
1344
|
removed.push(dir2);
|
|
1190
1345
|
}
|
|
1191
1346
|
return removed;
|
|
1192
1347
|
}
|
|
1193
1348
|
const dir = roleDir(role, projectRoot);
|
|
1194
|
-
if (
|
|
1349
|
+
if (existsSync2(dir)) {
|
|
1195
1350
|
rmSync3(dir, { recursive: true, force: true });
|
|
1196
1351
|
removed.push(dir);
|
|
1197
1352
|
}
|
|
@@ -1199,20 +1354,20 @@ function resetProjectAgentIdentity(role, projectRoot) {
|
|
|
1199
1354
|
}
|
|
1200
1355
|
function refreshProjectAgentIdentity(role, projectRoot) {
|
|
1201
1356
|
const dir = roleDir(role, projectRoot);
|
|
1202
|
-
|
|
1357
|
+
mkdirSync3(dir, { recursive: true });
|
|
1203
1358
|
for (const file of ["learned.md", "identity.md", "consolidated.md", "consolidation.json"]) {
|
|
1204
|
-
const fp =
|
|
1359
|
+
const fp = path5.join(dir, file);
|
|
1205
1360
|
try {
|
|
1206
1361
|
rmSync3(fp, { force: true });
|
|
1207
1362
|
} catch {
|
|
1208
1363
|
}
|
|
1209
1364
|
}
|
|
1210
1365
|
writeTextAtomically(
|
|
1211
|
-
|
|
1366
|
+
path5.join(dir, "learned.md"),
|
|
1212
1367
|
renderLearnedInstructions(role, [], (/* @__PURE__ */ new Date()).toISOString())
|
|
1213
1368
|
);
|
|
1214
1369
|
writeTextAtomically(
|
|
1215
|
-
|
|
1370
|
+
path5.join(dir, "identity.md"),
|
|
1216
1371
|
`# Project identity for ${role}
|
|
1217
1372
|
|
|
1218
1373
|
<!-- Describe how this agent should behave in the context of this project. -->
|
|
@@ -1223,9 +1378,9 @@ function refreshProjectAgentIdentity(role, projectRoot) {
|
|
|
1223
1378
|
function listProjectAgentRoles(projectRoot) {
|
|
1224
1379
|
const dir = agentsDir(projectRoot);
|
|
1225
1380
|
try {
|
|
1226
|
-
return
|
|
1381
|
+
return readdirSync(dir).filter((name) => {
|
|
1227
1382
|
if (!isProjectAgentRoleName(name)) return false;
|
|
1228
|
-
const sub =
|
|
1383
|
+
const sub = path5.join(dir, name);
|
|
1229
1384
|
try {
|
|
1230
1385
|
return [
|
|
1231
1386
|
"learned.md",
|
|
@@ -1236,7 +1391,7 @@ function listProjectAgentRoles(projectRoot) {
|
|
|
1236
1391
|
"profile.json",
|
|
1237
1392
|
"consolidated.md",
|
|
1238
1393
|
"consolidation.json"
|
|
1239
|
-
].some((file) =>
|
|
1394
|
+
].some((file) => existsSync2(path5.join(sub, file)));
|
|
1240
1395
|
} catch {
|
|
1241
1396
|
return false;
|
|
1242
1397
|
}
|
|
@@ -1246,6 +1401,96 @@ function listProjectAgentRoles(projectRoot) {
|
|
|
1246
1401
|
}
|
|
1247
1402
|
}
|
|
1248
1403
|
|
|
1404
|
+
// src/coordination/agents/project-agent-profile.ts
|
|
1405
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync4, readdirSync as readdirSync2, readFileSync as readFileSync5 } from "node:fs";
|
|
1406
|
+
import * as path6 from "node:path";
|
|
1407
|
+
function slugifyProjectAgentRole(name) {
|
|
1408
|
+
const slug = name.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^[._-]+|[._-]+$/g, "").slice(0, 96);
|
|
1409
|
+
return assertProjectAgentRole(slug);
|
|
1410
|
+
}
|
|
1411
|
+
function loadProjectAgentProfile(role, projectRoot) {
|
|
1412
|
+
try {
|
|
1413
|
+
const parsed = JSON.parse(
|
|
1414
|
+
readFileSync5(projectAgentProfilePath(role, projectRoot), "utf8")
|
|
1415
|
+
);
|
|
1416
|
+
const normalizedRole = assertProjectAgentRole(parsed.role ?? role);
|
|
1417
|
+
const baseRole = assertProjectAgentRole(parsed.baseRole ?? "generic");
|
|
1418
|
+
if (normalizedRole !== assertProjectAgentRole(role)) return void 0;
|
|
1419
|
+
if (typeof parsed.name !== "string" || !parsed.name.trim()) return void 0;
|
|
1420
|
+
if (typeof parsed.purpose !== "string" || !parsed.purpose.trim()) return void 0;
|
|
1421
|
+
if (!Array.isArray(parsed.taskTypes) || parsed.taskTypes.some((item) => typeof item !== "string")) {
|
|
1422
|
+
return void 0;
|
|
1423
|
+
}
|
|
1424
|
+
const createdAt = typeof parsed.createdAt === "string" ? parsed.createdAt : (/* @__PURE__ */ new Date(0)).toISOString();
|
|
1425
|
+
const updatedAt = typeof parsed.updatedAt === "string" ? parsed.updatedAt : createdAt;
|
|
1426
|
+
return {
|
|
1427
|
+
role: normalizedRole,
|
|
1428
|
+
name: parsed.name.trim(),
|
|
1429
|
+
baseRole,
|
|
1430
|
+
purpose: parsed.purpose.trim(),
|
|
1431
|
+
taskTypes: parsed.taskTypes.map((item) => item.trim()).filter(Boolean),
|
|
1432
|
+
createdAt,
|
|
1433
|
+
updatedAt
|
|
1434
|
+
};
|
|
1435
|
+
} catch {
|
|
1436
|
+
return void 0;
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
function createProjectAgent(input, projectRoot) {
|
|
1440
|
+
const name = input.name.trim();
|
|
1441
|
+
const purpose = input.purpose.trim();
|
|
1442
|
+
if (!name || name.length > 120) throw new Error("Project agent name must be 1-120 characters.");
|
|
1443
|
+
if (purpose.length < 10 || purpose.length > 4e3) {
|
|
1444
|
+
throw new Error("Project agent purpose must be 10-4000 characters.");
|
|
1445
|
+
}
|
|
1446
|
+
const role = assertProjectAgentRole(
|
|
1447
|
+
(input.role?.trim() || slugifyProjectAgentRole(name)).toLowerCase()
|
|
1448
|
+
);
|
|
1449
|
+
const baseRole = assertProjectAgentRole((input.baseRole?.trim() || "generic").toLowerCase());
|
|
1450
|
+
const taskTypes = [...new Set(input.taskTypes.map((item) => item.trim()).filter(Boolean))];
|
|
1451
|
+
if (taskTypes.length === 0 || taskTypes.length > 32 || taskTypes.some((item) => item.length > 160)) {
|
|
1452
|
+
throw new Error("Project agent requires 1-32 task descriptions, each at most 160 characters.");
|
|
1453
|
+
}
|
|
1454
|
+
const dir = roleDir(role, projectRoot);
|
|
1455
|
+
if (existsSync3(dir) && readdirSync2(dir).length > 0) {
|
|
1456
|
+
throw new Error(`Project agent role "${role}" already exists.`);
|
|
1457
|
+
}
|
|
1458
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1459
|
+
const profile = {
|
|
1460
|
+
role,
|
|
1461
|
+
name,
|
|
1462
|
+
baseRole,
|
|
1463
|
+
purpose,
|
|
1464
|
+
taskTypes,
|
|
1465
|
+
createdAt: now,
|
|
1466
|
+
updatedAt: now
|
|
1467
|
+
};
|
|
1468
|
+
const identity = [
|
|
1469
|
+
`# ${name}`,
|
|
1470
|
+
"",
|
|
1471
|
+
`You are the project-specific "${name}" agent (role: ${role}).`,
|
|
1472
|
+
"",
|
|
1473
|
+
"## Purpose",
|
|
1474
|
+
"",
|
|
1475
|
+
purpose,
|
|
1476
|
+
"",
|
|
1477
|
+
"## Primary task types",
|
|
1478
|
+
"",
|
|
1479
|
+
...taskTypes.map((item) => `- ${item}`),
|
|
1480
|
+
"",
|
|
1481
|
+
"Learn durable project conventions from completed work, keep conclusions evidence-based, and stay within this assigned purpose.",
|
|
1482
|
+
""
|
|
1483
|
+
].join("\n");
|
|
1484
|
+
mkdirSync4(dir, { recursive: true });
|
|
1485
|
+
writeTextAtomically(path6.join(dir, "identity.md"), identity);
|
|
1486
|
+
writeTextAtomically(
|
|
1487
|
+
projectAgentProfilePath(role, projectRoot),
|
|
1488
|
+
`${JSON.stringify(profile, null, 2)}
|
|
1489
|
+
`
|
|
1490
|
+
);
|
|
1491
|
+
return profile;
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1249
1494
|
// src/coordination/agents/project-agent-identity.ts
|
|
1250
1495
|
function createProjectAgentRoster(baseRoster, projectRoot) {
|
|
1251
1496
|
const target = { ...baseRoster };
|
|
@@ -1341,6 +1586,7 @@ function applyProjectAgentConfig(base, projectConfig, options = {}) {
|
|
|
1341
1586
|
const result = { ...base };
|
|
1342
1587
|
if (projectConfig.tools !== void 0) {
|
|
1343
1588
|
result.tools = options.protectSystemRole ? base.tools === void 0 ? void 0 : [.../* @__PURE__ */ new Set([...base.tools, ...projectConfig.tools])] : [...projectConfig.tools];
|
|
1589
|
+
result.capabilities = inferRuntimeCapabilities(result.tools ?? []);
|
|
1344
1590
|
}
|
|
1345
1591
|
if (projectConfig.skillNames !== void 0) result.skillNames = [...projectConfig.skillNames];
|
|
1346
1592
|
if (projectConfig.provider !== void 0) result.provider = projectConfig.provider;
|
|
@@ -1941,6 +2187,64 @@ function isDirectory(candidate) {
|
|
|
1941
2187
|
}
|
|
1942
2188
|
}
|
|
1943
2189
|
|
|
2190
|
+
// src/coordination/agents/types.ts
|
|
2191
|
+
var HOUR = 60 * 60 * 1e3;
|
|
2192
|
+
var LIGHT_BUDGET = {
|
|
2193
|
+
timeoutMs: 3 * HOUR,
|
|
2194
|
+
maxIterations: 3e3,
|
|
2195
|
+
maxToolCalls: 8e3
|
|
2196
|
+
};
|
|
2197
|
+
var MEDIUM_BUDGET = {
|
|
2198
|
+
timeoutMs: 5 * HOUR,
|
|
2199
|
+
maxIterations: 5e3,
|
|
2200
|
+
maxToolCalls: 14e3
|
|
2201
|
+
};
|
|
2202
|
+
var HEAVY_BUDGET = {
|
|
2203
|
+
timeoutMs: 10 * HOUR,
|
|
2204
|
+
maxIterations: 8e3,
|
|
2205
|
+
maxToolCalls: 2e4
|
|
2206
|
+
};
|
|
2207
|
+
var TOOLS = {
|
|
2208
|
+
/** Pure read/inspect — safe for analysis and review agents. */
|
|
2209
|
+
read: ["read", "grep", "glob", "search", "tree", "mailbox"],
|
|
2210
|
+
/** Read + structured inspection (logs, diffs, json, dependency audit). */
|
|
2211
|
+
inspect: ["read", "grep", "glob", "search", "tree", "json", "diff", "logs", "audit", "mailbox"],
|
|
2212
|
+
/** Read + edit (no shell). For agents that write code/docs but don't run it. */
|
|
2213
|
+
write: ["read", "grep", "glob", "search", "tree", "write", "edit", "replace", "patch", "mailbox"],
|
|
2214
|
+
/** Full build loop: edit + run (lint/format/typecheck/test/bash). */
|
|
2215
|
+
build: [
|
|
2216
|
+
"read",
|
|
2217
|
+
"grep",
|
|
2218
|
+
"glob",
|
|
2219
|
+
"search",
|
|
2220
|
+
"tree",
|
|
2221
|
+
"write",
|
|
2222
|
+
"edit",
|
|
2223
|
+
"replace",
|
|
2224
|
+
"patch",
|
|
2225
|
+
"bash",
|
|
2226
|
+
"exec",
|
|
2227
|
+
"lint",
|
|
2228
|
+
"format",
|
|
2229
|
+
"typecheck",
|
|
2230
|
+
"test",
|
|
2231
|
+
"mailbox"
|
|
2232
|
+
],
|
|
2233
|
+
/** Version control. */
|
|
2234
|
+
vcs: ["read", "grep", "glob", "git", "diff"],
|
|
2235
|
+
/** Dependency management + CVE audit. */
|
|
2236
|
+
deps: ["read", "grep", "glob", "install", "outdated", "audit", "json", "mailbox"],
|
|
2237
|
+
/** Documentation authoring. */
|
|
2238
|
+
docs: ["read", "grep", "glob", "search", "tree", "write", "edit", "document", "mailbox"],
|
|
2239
|
+
/** Web research. */
|
|
2240
|
+
research: ["read", "grep", "glob", "search", "fetch", "mailbox"]
|
|
2241
|
+
};
|
|
2242
|
+
var SPECIALIST_TOOLS = {
|
|
2243
|
+
browser: toolsForRuntimeCapabilities(["browser.interact"]),
|
|
2244
|
+
memory: toolsForRuntimeCapabilities(["memory.manage"]),
|
|
2245
|
+
mcp: toolsForRuntimeCapabilities(["mcp.dynamic"])
|
|
2246
|
+
};
|
|
2247
|
+
|
|
1944
2248
|
// src/coordination/agents/phase1-discovery.ts
|
|
1945
2249
|
var DISCOVERY_AGENTS = [
|
|
1946
2250
|
{
|
|
@@ -1976,7 +2280,7 @@ var DISCOVERY_AGENTS = [
|
|
|
1976
2280
|
id: "search",
|
|
1977
2281
|
name: "Search",
|
|
1978
2282
|
role: "search",
|
|
1979
|
-
tools: [...TOOLS.read],
|
|
2283
|
+
tools: [...TOOLS.read, "codebase-search"],
|
|
1980
2284
|
prompt: agentPrompt("search")
|
|
1981
2285
|
},
|
|
1982
2286
|
budget: MEDIUM_BUDGET,
|
|
@@ -2438,14 +2742,7 @@ var WAVE1_AGENTS = [
|
|
|
2438
2742
|
capability: {
|
|
2439
2743
|
phase: "domain",
|
|
2440
2744
|
summary: "Android platform specialist: Kotlin, Jetpack Compose, Android SDK, lifecycle and Play Store delivery.",
|
|
2441
|
-
keywords: [
|
|
2442
|
-
...ANDROID_META.signals,
|
|
2443
|
-
"android",
|
|
2444
|
-
"kotlin",
|
|
2445
|
-
"compose",
|
|
2446
|
-
"gradle",
|
|
2447
|
-
"playstore"
|
|
2448
|
-
]
|
|
2745
|
+
keywords: [...ANDROID_META.signals, "android", "kotlin", "compose", "gradle", "playstore"]
|
|
2449
2746
|
}
|
|
2450
2747
|
},
|
|
2451
2748
|
{
|
|
@@ -2460,14 +2757,7 @@ var WAVE1_AGENTS = [
|
|
|
2460
2757
|
capability: {
|
|
2461
2758
|
phase: "domain",
|
|
2462
2759
|
summary: "Desktop application specialist: Electron or Tauri, native packaging, IPC and OS integration.",
|
|
2463
|
-
keywords: [
|
|
2464
|
-
...DESKTOP_META.signals,
|
|
2465
|
-
"desktop",
|
|
2466
|
-
"electron",
|
|
2467
|
-
"tauri",
|
|
2468
|
-
"ipc",
|
|
2469
|
-
"tray"
|
|
2470
|
-
]
|
|
2760
|
+
keywords: [...DESKTOP_META.signals, "desktop", "electron", "tauri", "ipc", "tray"]
|
|
2471
2761
|
}
|
|
2472
2762
|
},
|
|
2473
2763
|
{
|
|
@@ -2543,7 +2833,7 @@ var WAVE1_AGENTS = [
|
|
|
2543
2833
|
id: "platform-engineer",
|
|
2544
2834
|
name: "Platform Engineer",
|
|
2545
2835
|
role: "platform-engineer",
|
|
2546
|
-
tools: [...TOOLS.build, "install", "git"
|
|
2836
|
+
tools: [...TOOLS.build, "install", "git"],
|
|
2547
2837
|
prompt: agentPrompt("platform-engineer")
|
|
2548
2838
|
},
|
|
2549
2839
|
budget: MEDIUM_BUDGET,
|
|
@@ -2787,8 +3077,7 @@ var WAVE2_AGENTS = [
|
|
|
2787
3077
|
id: "resilience-engineer",
|
|
2788
3078
|
name: "Resilience Engineer",
|
|
2789
3079
|
role: "resilience-engineer",
|
|
2790
|
-
tools: [...TOOLS.build, "logs"
|
|
2791
|
-
// uniqueness guaranteed by 'observability' vs chaos-engineer's 'test'
|
|
3080
|
+
tools: [...TOOLS.build, "logs"],
|
|
2792
3081
|
prompt: agentPrompt("resilience-engineer")
|
|
2793
3082
|
},
|
|
2794
3083
|
budget: MEDIUM_BUDGET,
|
|
@@ -2811,8 +3100,7 @@ var WAVE2_AGENTS = [
|
|
|
2811
3100
|
id: "chaos-engineer",
|
|
2812
3101
|
name: "Chaos Engineer",
|
|
2813
3102
|
role: "chaos-engineer",
|
|
2814
|
-
tools: [...TOOLS.build, "logs"
|
|
2815
|
-
// uniqueness guaranteed by 'observability' vs chaos-engineer's 'test'
|
|
3103
|
+
tools: [...TOOLS.build, "logs"],
|
|
2816
3104
|
prompt: agentPrompt("chaos-engineer")
|
|
2817
3105
|
},
|
|
2818
3106
|
budget: MEDIUM_BUDGET,
|
|
@@ -2953,21 +3241,7 @@ var VERIFY_AGENTS = [
|
|
|
2953
3241
|
id: "e2e",
|
|
2954
3242
|
name: "E2E",
|
|
2955
3243
|
role: "e2e",
|
|
2956
|
-
tools: [
|
|
2957
|
-
...TOOLS.build,
|
|
2958
|
-
"fetch",
|
|
2959
|
-
"playwright_navigate",
|
|
2960
|
-
"playwright_screenshot",
|
|
2961
|
-
"playwright_click",
|
|
2962
|
-
"playwright_type",
|
|
2963
|
-
"playwright_evaluate",
|
|
2964
|
-
"playwright_select_option",
|
|
2965
|
-
"playwright_hover",
|
|
2966
|
-
"playwright_fill_form",
|
|
2967
|
-
"playwright_wait_for",
|
|
2968
|
-
"playwright_press_key",
|
|
2969
|
-
"playwright_drag"
|
|
2970
|
-
],
|
|
3244
|
+
tools: [...TOOLS.build, "fetch", ...SPECIALIST_TOOLS.browser],
|
|
2971
3245
|
prompt: agentPrompt("e2e")
|
|
2972
3246
|
},
|
|
2973
3247
|
budget: HEAVY_BUDGET,
|
|
@@ -3002,21 +3276,7 @@ var VERIFY_AGENTS = [
|
|
|
3002
3276
|
id: "browser",
|
|
3003
3277
|
name: "Browser",
|
|
3004
3278
|
role: "browser",
|
|
3005
|
-
tools: [
|
|
3006
|
-
...TOOLS.read,
|
|
3007
|
-
"fetch",
|
|
3008
|
-
"playwright_navigate",
|
|
3009
|
-
"playwright_screenshot",
|
|
3010
|
-
"playwright_click",
|
|
3011
|
-
"playwright_type",
|
|
3012
|
-
"playwright_evaluate",
|
|
3013
|
-
"playwright_select_option",
|
|
3014
|
-
"playwright_hover",
|
|
3015
|
-
"playwright_fill_form",
|
|
3016
|
-
"playwright_wait_for",
|
|
3017
|
-
"playwright_press_key",
|
|
3018
|
-
"playwright_drag"
|
|
3019
|
-
],
|
|
3279
|
+
tools: [...TOOLS.read, "fetch", ...SPECIALIST_TOOLS.browser],
|
|
3020
3280
|
prompt: agentPrompt("browser")
|
|
3021
3281
|
},
|
|
3022
3282
|
budget: MEDIUM_BUDGET,
|
|
@@ -3717,27 +3977,7 @@ var DELIVERY_AGENTS = [
|
|
|
3717
3977
|
id: "devops",
|
|
3718
3978
|
name: "DevOps",
|
|
3719
3979
|
role: "devops",
|
|
3720
|
-
tools: [
|
|
3721
|
-
...TOOLS.build,
|
|
3722
|
-
"mcp__ssh__ssh_list_servers",
|
|
3723
|
-
"mcp__ssh__ssh_connection_status",
|
|
3724
|
-
"mcp__ssh__ssh_execute",
|
|
3725
|
-
"mcp__ssh__ssh_execute_sudo",
|
|
3726
|
-
"mcp__ssh__ssh_upload",
|
|
3727
|
-
"mcp__ssh__ssh_download",
|
|
3728
|
-
"mcp__ssh__ssh_sync",
|
|
3729
|
-
"mcp__ssh__ssh_deploy",
|
|
3730
|
-
"mcp__ssh__ssh_health_check",
|
|
3731
|
-
"mcp__ssh__ssh_service_status",
|
|
3732
|
-
"mcp__ssh__ssh_process_manager",
|
|
3733
|
-
"mcp__ssh__ssh_tunnel",
|
|
3734
|
-
"mcp__ssh__ssh_backup_create",
|
|
3735
|
-
"mcp__ssh__ssh_backup_list",
|
|
3736
|
-
"mcp__ssh__ssh_backup_restore",
|
|
3737
|
-
"mcp__ssh__ssh_db_list",
|
|
3738
|
-
"mcp__ssh__ssh_db_query",
|
|
3739
|
-
"mcp__ssh__ssh_profile"
|
|
3740
|
-
],
|
|
3980
|
+
tools: [...TOOLS.build, ...SPECIALIST_TOOLS.mcp],
|
|
3741
3981
|
prompt: agentPrompt("devops")
|
|
3742
3982
|
},
|
|
3743
3983
|
budget: MEDIUM_BUDGET,
|
|
@@ -3938,7 +4178,7 @@ var WAVE3_AGENTS = [
|
|
|
3938
4178
|
id: "messaging",
|
|
3939
4179
|
name: "Messaging",
|
|
3940
4180
|
role: "messaging",
|
|
3941
|
-
tools: [...TOOLS.build, "logs"
|
|
4181
|
+
tools: [...TOOLS.build, "logs"],
|
|
3942
4182
|
prompt: agentPrompt("messaging")
|
|
3943
4183
|
},
|
|
3944
4184
|
budget: HEAVY_BUDGET,
|
|
@@ -4379,7 +4619,7 @@ var WAVE4_AGENTS = [
|
|
|
4379
4619
|
id: "memory-curator",
|
|
4380
4620
|
name: "Memory Curator",
|
|
4381
4621
|
role: "memory-curator",
|
|
4382
|
-
tools: [...TOOLS.read,
|
|
4622
|
+
tools: [...TOOLS.read, ...SPECIALIST_TOOLS.memory],
|
|
4383
4623
|
prompt: agentPrompt("memory-curator")
|
|
4384
4624
|
},
|
|
4385
4625
|
budget: LIGHT_BUDGET,
|
|
@@ -4401,7 +4641,7 @@ var WAVE4_AGENTS = [
|
|
|
4401
4641
|
id: "fleet-coordinator",
|
|
4402
4642
|
name: "Fleet Coordinator",
|
|
4403
4643
|
role: "fleet-coordinator",
|
|
4404
|
-
tools: [...TOOLS.read, "plan"
|
|
4644
|
+
tools: [...TOOLS.read, "plan"],
|
|
4405
4645
|
prompt: agentPrompt("fleet-coordinator")
|
|
4406
4646
|
},
|
|
4407
4647
|
budget: MEDIUM_BUDGET,
|
|
@@ -4527,8 +4767,20 @@ var ROLE_SKILL_SETS = {
|
|
|
4527
4767
|
cost: skillSet("audit-log", "tech-stack", "observability", "research-web"),
|
|
4528
4768
|
"tech-stack": skillSet("tech-stack", "research-web", "security-scanner", "node-modern"),
|
|
4529
4769
|
// ── Wave 1: Platform and systems engineering ──────────────────────────
|
|
4530
|
-
android: skillSet(
|
|
4531
|
-
|
|
4770
|
+
android: skillSet(
|
|
4771
|
+
"react-modern",
|
|
4772
|
+
"typescript-strict",
|
|
4773
|
+
"testing",
|
|
4774
|
+
"security-scanner",
|
|
4775
|
+
"tech-stack"
|
|
4776
|
+
),
|
|
4777
|
+
desktop: skillSet(
|
|
4778
|
+
"node-modern",
|
|
4779
|
+
"typescript-strict",
|
|
4780
|
+
"testing",
|
|
4781
|
+
"security-scanner",
|
|
4782
|
+
"tech-stack"
|
|
4783
|
+
),
|
|
4532
4784
|
realtime: skillSet(
|
|
4533
4785
|
"api-design",
|
|
4534
4786
|
"observability",
|
|
@@ -4632,26 +4884,9 @@ var ROLE_SKILL_SETS = {
|
|
|
4632
4884
|
"security-scanner",
|
|
4633
4885
|
"tech-stack"
|
|
4634
4886
|
),
|
|
4635
|
-
"benchmark-engineer": skillSet(
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
"output-standards",
|
|
4639
|
-
"tech-stack"
|
|
4640
|
-
),
|
|
4641
|
-
"memory-curator": skillSet(
|
|
4642
|
-
"mnemosyne",
|
|
4643
|
-
"audit-log",
|
|
4644
|
-
"testing",
|
|
4645
|
-
"output-standards",
|
|
4646
|
-
"tech-stack"
|
|
4647
|
-
),
|
|
4648
|
-
"fleet-coordinator": skillSet(
|
|
4649
|
-
"multi-agent",
|
|
4650
|
-
"sdd",
|
|
4651
|
-
"output-standards",
|
|
4652
|
-
"testing",
|
|
4653
|
-
"tech-stack"
|
|
4654
|
-
),
|
|
4887
|
+
"benchmark-engineer": skillSet("observability", "testing", "output-standards", "tech-stack"),
|
|
4888
|
+
"memory-curator": skillSet("mnemosyne", "audit-log", "testing", "output-standards", "tech-stack"),
|
|
4889
|
+
"fleet-coordinator": skillSet("multi-agent", "sdd", "output-standards", "testing", "tech-stack"),
|
|
4655
4890
|
// ── Wave 2: Security, resilience, governance and agent platform ────────
|
|
4656
4891
|
"threat-modeler": skillSet(
|
|
4657
4892
|
"security-scanner",
|
|
@@ -4703,6 +4938,7 @@ var SHADOW_AGENT_SKILLS = skillSet(
|
|
|
4703
4938
|
"observability",
|
|
4704
4939
|
"security-scanner"
|
|
4705
4940
|
);
|
|
4941
|
+
var MAX_EAGER_ROSTER_SKILLS = 3;
|
|
4706
4942
|
function assignSkillsToAgents(definitions) {
|
|
4707
4943
|
return definitions.map((definition) => {
|
|
4708
4944
|
const role = definition.config.role;
|
|
@@ -4716,7 +4952,8 @@ function assignSkillsToAgents(definitions) {
|
|
|
4716
4952
|
...definition,
|
|
4717
4953
|
config: {
|
|
4718
4954
|
...definition.config,
|
|
4719
|
-
|
|
4955
|
+
capabilities: inferRuntimeCapabilities(definition.config.tools ?? []),
|
|
4956
|
+
skillNames: skills.slice(0, MAX_EAGER_ROSTER_SKILLS)
|
|
4720
4957
|
}
|
|
4721
4958
|
};
|
|
4722
4959
|
});
|
|
@@ -4789,7 +5026,9 @@ export {
|
|
|
4789
5026
|
PLANNING_AGENTS,
|
|
4790
5027
|
REVIEW_AGENTS,
|
|
4791
5028
|
ROLE_SKILL_SETS,
|
|
5029
|
+
RUNTIME_CAPABILITY_MANIFEST,
|
|
4792
5030
|
SHADOW_AGENT_SKILLS,
|
|
5031
|
+
SPECIALIST_TOOLS,
|
|
4793
5032
|
TOOLS,
|
|
4794
5033
|
VERIFY_AGENTS,
|
|
4795
5034
|
WAVE1_AGENTS,
|
|
@@ -4822,7 +5061,10 @@ export {
|
|
|
4822
5061
|
getAgentDefinition,
|
|
4823
5062
|
getProjectAgentLearnStats,
|
|
4824
5063
|
hintLearnedNeedsSummarization,
|
|
5064
|
+
inferRuntimeCapabilities,
|
|
4825
5065
|
isConsolidated,
|
|
5066
|
+
isDeprecatedRuntimeToolAlias,
|
|
5067
|
+
isKnownRuntimeCapability,
|
|
4826
5068
|
listProjectAgentLearnedEntries,
|
|
4827
5069
|
listProjectAgentRoles,
|
|
4828
5070
|
loadConsolidationMetadata,
|
|
@@ -4834,14 +5076,20 @@ export {
|
|
|
4834
5076
|
loadProjectAgentProfile,
|
|
4835
5077
|
loadRoleKnowledgeManifest,
|
|
4836
5078
|
mergeStructuredEntries,
|
|
5079
|
+
missingRequiredRuntimeTools,
|
|
5080
|
+
missingRuntimeCapabilities,
|
|
4837
5081
|
normalizeLearnedEntry,
|
|
5082
|
+
normalizeRuntimeToolName,
|
|
4838
5083
|
parseLearnedEntryStamp,
|
|
4839
5084
|
parseStructuredLearnedEntries,
|
|
4840
5085
|
refreshProjectAgentIdentity,
|
|
4841
5086
|
renderLearnedInstructions,
|
|
4842
5087
|
resetProjectAgentIdentity,
|
|
5088
|
+
runtimeCapabilityForTool,
|
|
5089
|
+
runtimeToolReferencesFromText,
|
|
4843
5090
|
saveProjectAgentConsolidated,
|
|
4844
5091
|
slugifyProjectAgentRole,
|
|
5092
|
+
toolsForRuntimeCapabilities,
|
|
4845
5093
|
updateProjectAgentConfig,
|
|
4846
5094
|
updateProjectAgentIdentity,
|
|
4847
5095
|
updateProjectAgentKnowledge,
|