@praxis-ai/praxis 0.1.4 → 0.1.6

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.
Files changed (64) hide show
  1. package/dist/agentCore/index.d.ts +29 -3
  2. package/dist/agentCore/index.js +3 -0
  3. package/dist/applicationLayer/applicationRuntime.js +7 -1
  4. package/dist/basetool/authoring.d.ts +2 -0
  5. package/dist/basetool/authoring.js +2 -0
  6. package/dist/basetool/catalog.d.ts +1 -1
  7. package/dist/basetool/catalog.js +86 -4
  8. package/dist/basetool/core/index.d.ts +4 -2
  9. package/dist/basetool/core/index.js +8 -0
  10. package/dist/basetool/core/mcpCompletions.d.ts +2 -0
  11. package/dist/basetool/core/mcpCompletions.js +70 -0
  12. package/dist/basetool/core/mcpPrompts.d.ts +2 -0
  13. package/dist/basetool/core/mcpPrompts.js +48 -0
  14. package/dist/basetool/core/mcpResources.js +41 -5
  15. package/dist/basetool/profiles.js +15 -1
  16. package/dist/basetool/registry.d.ts +1 -1
  17. package/dist/basetool/supportCatalog.js +23 -6
  18. package/dist/executionEngine/promptPack/promptAssembler.js +1 -0
  19. package/dist/executionEngine/promptPack/promptDefiner.d.ts +4 -4
  20. package/dist/executionEngine/promptPack/promptDefiner.js +1 -0
  21. package/dist/runtimeImplementation/praxisRuntimeKernel.d.ts +4 -0
  22. package/dist/runtimeImplementation/praxisRuntimeKernel.js +1729 -1498
  23. package/dist/runtimeImplementation/runtime.execEngine/baseToolApprovalScope.js +11 -0
  24. package/dist/runtimeImplementation/runtime.execEngine/baseToolExecutorPortFactory.js +13 -1
  25. package/dist/runtimeImplementation/runtime.execEngine/baseToolPolicyAdjudicator.js +14 -0
  26. package/dist/runtimeImplementation/runtime.execEngine/mcpRuntimeAdapter.d.ts +27 -0
  27. package/dist/runtimeImplementation/runtime.execEngine/mcpRuntimeAdapter.js +648 -56
  28. package/dist/runtimeImplementation/runtime.execEngine/promptContextAssembly.d.ts +2 -0
  29. package/dist/runtimeImplementation/runtime.execEngine/promptContextAssembly.js +35 -0
  30. package/dist/runtimeImplementation/runtime.mcpPlane/index.d.ts +20 -7
  31. package/dist/runtimeImplementation/runtime.mcpPlane/index.js +105 -89
  32. package/dist/runtimeImplementation/runtime.skillPlane/index.d.ts +119 -0
  33. package/dist/runtimeImplementation/runtime.skillPlane/index.js +274 -0
  34. package/dist/runtimeImplementation/runtimeAgentManifest.js +2 -0
  35. package/dist/toolBase/catalog.d.ts +24 -0
  36. package/dist/toolBase/catalog.js +41 -3
  37. package/dist/toolBase/profiles.d.ts +3 -3
  38. package/dist/toolBase/profiles.js +2 -0
  39. package/dist/toolBase/types.d.ts +1 -1
  40. package/examples/fullstack/agents/repoInspector/harness/repoInspectorHarness.ts +23 -0
  41. package/examples/raxode-mcp-plus-ten-server.config.json +229 -0
  42. package/examples/scripts/README.md +8 -2
  43. package/examples/scripts/mcp-plus-native-smoke.ts +1296 -0
  44. package/package.json +3 -1
  45. package/raxode-tui/dist/raxode-cli/backend/agents/codingAgent/prompts/tool-use.md +1 -1
  46. package/raxode-tui/dist/raxode-cli/backend/application/mcpConfig.d.ts +9 -0
  47. package/raxode-tui/dist/raxode-cli/backend/application/mcpConfig.js +65 -0
  48. package/raxode-tui/dist/raxode-cli/backend/application/mcpReadinessSummary.d.ts +28 -0
  49. package/raxode-tui/dist/raxode-cli/backend/application/mcpReadinessSummary.js +57 -0
  50. package/raxode-tui/dist/raxode-cli/backend/application/runtimeReadiness.d.ts +5 -1
  51. package/raxode-tui/dist/raxode-cli/backend/application/runtimeReadiness.js +40 -0
  52. package/raxode-tui/dist/raxode-cli/backend/application/stdioApplicationServer.js +6 -0
  53. package/raxode-tui/dist/raxode-cli/backend/directApplicationBackend.d.ts +4 -0
  54. package/raxode-tui/dist/raxode-cli/backend/directApplicationBackend.js +14 -0
  55. package/raxode-tui/dist/raxode-cli/backend/raxodeBackend.d.ts +1 -1
  56. package/raxode-tui/dist/raxode-cli/backend/raxodeBackend.js +16 -1
  57. package/raxode-tui/dist/raxode-cli/contracts.d.ts +1 -0
  58. package/raxode-tui/dist/raxode-cli/frontend/bridge/readiness.js +24 -0
  59. package/raxode-tui/dist/raxode-cli/frontend/tui/app/direct-tui.js +35 -0
  60. package/raxode-tui/dist/raxode-cli/frontend/tui/cli/raxode-cli.d.ts +2 -0
  61. package/raxode-tui/dist/raxode-cli/frontend/tui/cli/raxode-cli.js +8 -0
  62. package/raxode-tui/dist/raxode-cli/frontend/tui/config/raxode-config.d.ts +31 -0
  63. package/raxode-tui/dist/raxode-cli/frontend/tui/config/raxode-config.js +129 -0
  64. package/raxode-tui/dist/raxode-cli/index.d.ts +1 -0
@@ -0,0 +1,274 @@
1
+ /*
2
+ * 文件定位:Runtime Skill Plane / 技能索引与按需正文加载合约。
3
+ * 核心目的:让 Praxis runtime 能声明、索引、读取和写入可复用技能经验,
4
+ * 但不把技能直接降级成工具声明或外部服务配置。
5
+ */
6
+ import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
7
+ import { createHash } from "node:crypto";
8
+ import path from "node:path";
9
+ const DEFAULT_INDEX_POLICY = {
10
+ maxHeads: 40,
11
+ includeScopes: ["agent", "project", "workspace"],
12
+ };
13
+ const DEFAULT_BODY_LOAD_POLICY = {
14
+ mode: "on-demand",
15
+ maxBodiesPerTurn: 3,
16
+ };
17
+ const DEFAULT_LIFECYCLE_POLICY = {
18
+ allowWrite: true,
19
+ checkpointWrites: true,
20
+ promotion: "suggest",
21
+ };
22
+ export const skill = {
23
+ directory(directoryPath, input) {
24
+ return input === undefined
25
+ ? { kind: "directory", path: directoryPath }
26
+ : { kind: "directory", path: directoryPath, scope: input.scope };
27
+ },
28
+ package(packageName, input) {
29
+ return input === undefined
30
+ ? { kind: "package", packageName }
31
+ : { kind: "package", packageName, scope: input.scope };
32
+ },
33
+ inline(heads) {
34
+ return { kind: "inline", heads };
35
+ },
36
+ module(input = {}) {
37
+ return {
38
+ kind: "praxis.skill.module",
39
+ version: "praxis.skill.v1",
40
+ sources: input.sources ?? [],
41
+ indexPolicy: {
42
+ ...DEFAULT_INDEX_POLICY,
43
+ ...input.indexPolicy,
44
+ },
45
+ bodyLoadPolicy: {
46
+ ...DEFAULT_BODY_LOAD_POLICY,
47
+ ...input.bodyLoadPolicy,
48
+ },
49
+ lifecycle: {
50
+ ...DEFAULT_LIFECYCLE_POLICY,
51
+ ...input.lifecycle,
52
+ },
53
+ metadata: input.metadata,
54
+ };
55
+ },
56
+ };
57
+ export function isSkillPlaneModuleSpec(value) {
58
+ if (typeof value !== "object" || value === null || Array.isArray(value))
59
+ return false;
60
+ const record = value;
61
+ return record.kind === "praxis.skill.module" && Array.isArray(record.sources);
62
+ }
63
+ export function skillPlaneModuleFrom(input) {
64
+ const candidate = input.modules?.skill;
65
+ return isSkillPlaneModuleSpec(candidate) ? candidate : undefined;
66
+ }
67
+ export function runtimeRequirementsForSkillModule(module) {
68
+ return module === undefined ? [] : ["runtime.skill"];
69
+ }
70
+ function isSkillHeadLike(value) {
71
+ if (typeof value !== "object" || value === null || Array.isArray(value))
72
+ return false;
73
+ const record = value;
74
+ return typeof record.skillId === "string" && typeof record.title === "string" && typeof record.summary === "string";
75
+ }
76
+ function headsFromUnknown(value) {
77
+ if (Array.isArray(value))
78
+ return value.filter(isSkillHeadLike);
79
+ if (typeof value !== "object" || value === null)
80
+ return [];
81
+ const record = value;
82
+ if (Array.isArray(record.skillHeads))
83
+ return record.skillHeads.filter(isSkillHeadLike);
84
+ if (Array.isArray(record.heads))
85
+ return record.heads.filter(isSkillHeadLike);
86
+ if (Array.isArray(record.skills))
87
+ return record.skills.filter(isSkillHeadLike);
88
+ return isSkillHeadLike(value) ? [value] : [];
89
+ }
90
+ function withSourceScope(heads, scope) {
91
+ if (scope === undefined)
92
+ return heads;
93
+ return heads.map((head) => ({
94
+ ...head,
95
+ scope: head.scope ?? scope,
96
+ }));
97
+ }
98
+ export async function loadSkillHeadsFromSource(source, input = {}) {
99
+ if (source.kind === "inline")
100
+ return source.heads;
101
+ if (source.kind === "package") {
102
+ const module = await import(source.packageName);
103
+ return withSourceScope([
104
+ ...headsFromUnknown(module.skillHeads),
105
+ ...headsFromUnknown(module.heads),
106
+ ...headsFromUnknown(module.skills),
107
+ ...headsFromUnknown(module.default),
108
+ ], source.scope);
109
+ }
110
+ const rootDir = path.isAbsolute(source.path)
111
+ ? source.path
112
+ : path.resolve(input.workspaceRoot ?? process.cwd(), source.path);
113
+ let entries;
114
+ try {
115
+ entries = await readdir(rootDir);
116
+ }
117
+ catch {
118
+ return [];
119
+ }
120
+ const heads = await Promise.all(entries
121
+ .filter((entry) => entry.endsWith(".json"))
122
+ .map((entry) => readJsonFile(path.join(rootDir, entry), undefined).then(headsFromUnknown)));
123
+ return withSourceScope(heads.flat(), source.scope);
124
+ }
125
+ export async function loadSkillHeadsFromSources(sources, input = {}) {
126
+ const heads = await Promise.all(sources.map((source) => loadSkillHeadsFromSource(source, input)));
127
+ return heads.flat();
128
+ }
129
+ function headFromBody(body) {
130
+ return {
131
+ skillId: body.skillId,
132
+ title: body.title,
133
+ summary: body.summary,
134
+ scope: body.scope,
135
+ whenToUse: body.whenToUse,
136
+ why: body.why,
137
+ keywords: body.keywords,
138
+ pitfallsPreview: body.pitfallsPreview,
139
+ bodyRef: body.bodyRef,
140
+ promotedFrom: body.promotedFrom,
141
+ promotionState: body.promotionState,
142
+ };
143
+ }
144
+ function scopeMatches(head, scopes) {
145
+ if (scopes === undefined || scopes.length === 0)
146
+ return true;
147
+ return head.scope !== undefined && scopes.includes(head.scope);
148
+ }
149
+ function sortHeads(heads) {
150
+ return [...heads].sort((left, right) => left.skillId.localeCompare(right.skillId));
151
+ }
152
+ export function createInMemorySkillPlaneStore(initialBodies = []) {
153
+ const bodies = new Map(initialBodies.map((body) => [body.skillId, body]));
154
+ return {
155
+ async listHeads(query) {
156
+ return sortHeads([...bodies.values()].map(headFromBody).filter((head) => scopeMatches(head, query?.scopes)));
157
+ },
158
+ async readBody(skillId) {
159
+ return bodies.get(skillId);
160
+ },
161
+ async write(body) {
162
+ bodies.set(body.skillId, body);
163
+ return body;
164
+ },
165
+ };
166
+ }
167
+ async function readJsonFile(filePath, fallback) {
168
+ try {
169
+ return JSON.parse(await readFile(filePath, "utf8"));
170
+ }
171
+ catch {
172
+ return fallback;
173
+ }
174
+ }
175
+ async function writeJsonFile(filePath, value) {
176
+ await mkdir(path.dirname(filePath), { recursive: true });
177
+ await writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, { mode: 0o600 });
178
+ }
179
+ function skillFilePart(skillId) {
180
+ const sanitized = skillId
181
+ .trim()
182
+ .replace(/[^a-zA-Z0-9._-]+/gu, "-")
183
+ .replace(/^[._-]+|[._-]+$/gu, "")
184
+ .slice(0, 64)
185
+ .toLowerCase() || "skill";
186
+ const stableSuffix = createHash("sha256").update(skillId).digest("hex").slice(0, 16);
187
+ return `${sanitized}-${stableSuffix}.json`;
188
+ }
189
+ export function createFileSkillPlaneStore(rootDir) {
190
+ function bodyPath(skillId) {
191
+ return path.join(rootDir, skillFilePart(skillId));
192
+ }
193
+ async function listBodies() {
194
+ let entries;
195
+ try {
196
+ entries = await readdir(rootDir);
197
+ }
198
+ catch {
199
+ return [];
200
+ }
201
+ const bodies = await Promise.all(entries
202
+ .filter((entry) => entry.endsWith(".json"))
203
+ .map((entry) => readJsonFile(path.join(rootDir, entry), undefined)));
204
+ return bodies.filter((body) => body !== undefined && typeof body.skillId === "string");
205
+ }
206
+ return {
207
+ async listHeads(query) {
208
+ return sortHeads((await listBodies()).map(headFromBody).filter((head) => scopeMatches(head, query?.scopes)));
209
+ },
210
+ async readBody(skillId) {
211
+ return await readJsonFile(bodyPath(skillId), undefined);
212
+ },
213
+ async write(body) {
214
+ await writeJsonFile(bodyPath(body.skillId), body);
215
+ return body;
216
+ },
217
+ };
218
+ }
219
+ function compactLine(label, value) {
220
+ if (value === undefined)
221
+ return undefined;
222
+ const rendered = typeof value === "string"
223
+ ? value.trim()
224
+ : value.map((item) => item.trim()).filter(Boolean).join(", ");
225
+ return rendered.length === 0 ? undefined : `${label}: ${rendered}`;
226
+ }
227
+ export function renderSkillIndexMaterial(heads) {
228
+ const lines = ["# Skill Plane Index"];
229
+ for (const head of sortHeads(heads)) {
230
+ lines.push(`- ${head.skillId}: ${head.title}. ${head.summary}`);
231
+ const detailLines = [
232
+ compactLine(" scope", head.scope),
233
+ compactLine(" when", head.whenToUse),
234
+ compactLine(" why", head.why),
235
+ compactLine(" keywords", head.keywords),
236
+ compactLine(" pitfalls preview", head.pitfallsPreview),
237
+ compactLine(" body ref", head.bodyRef),
238
+ compactLine(" promotion", head.promotionState),
239
+ ].filter((line) => line !== undefined);
240
+ lines.push(...detailLines);
241
+ }
242
+ return {
243
+ id: "runtime:skill-plane:index",
244
+ kind: "runtime",
245
+ source: "runtime.skillPlane.index",
246
+ sourceCategory: "declared-built-in",
247
+ trusted: true,
248
+ promptSegmentKind: "skillIndex",
249
+ metadata: {
250
+ promptSegmentKind: "skillIndex",
251
+ generatedBy: "runtime.skillPlane",
252
+ },
253
+ text: lines.join("\n"),
254
+ };
255
+ }
256
+ export function createSkillWriteProposal(body, input = {}) {
257
+ return {
258
+ kind: "praxis.skill.writeProposal",
259
+ body,
260
+ reason: input.reason,
261
+ safeForRuntimeInspection: true,
262
+ };
263
+ }
264
+ export function adviseSkillPromotion(skillHead, input = {}) {
265
+ return {
266
+ kind: "praxis.skill.promotionAdvice",
267
+ skillId: skillHead.skillId,
268
+ from: skillHead.promotionState,
269
+ target: "candidate-mcp-plus",
270
+ autoGenerateTool: false,
271
+ reason: input.reason,
272
+ signals: input.signals,
273
+ };
274
+ }
@@ -12,6 +12,7 @@ import { createBaseToolSupportCatalog } from "./runtime.execEngine/baseToolSuppo
12
12
  import { canonicalDependencyId, dependencyKindFromId, } from "./runtime.dependencyPlane/index.js";
13
13
  import { capability as capabilityAuthoring, } from "./runtime.provisionPlane/index.js";
14
14
  import { mcpHarnessModuleFrom, runtimeRequirementsForMcpModule, } from "./runtime.mcpPlane/index.js";
15
+ import { runtimeRequirementsForSkillModule, skillPlaneModuleFrom, } from "./runtime.skillPlane/index.js";
15
16
  export class PromptPack {
16
17
  promptPackId;
17
18
  base;
@@ -1272,6 +1273,7 @@ function normalizeHarness(input, authoring, normalizedTools) {
1272
1273
  runtimeRequirements: cleanList([
1273
1274
  ...(input.runtimeRequirements ?? []),
1274
1275
  ...runtimeRequirementsForMcpModule(mcpHarnessModuleFrom({ modules: input.modules })),
1276
+ ...runtimeRequirementsForSkillModule(skillPlaneModuleFrom({ modules: input.modules })),
1275
1277
  ]),
1276
1278
  capabilities: authoring.capabilities,
1277
1279
  dependencies: authoring.dependencies,
@@ -202,6 +202,30 @@ export declare const TOOL_BASE_CATALOG: ({
202
202
  aliases: string[];
203
203
  capabilityTags: string[];
204
204
  requiresRuntimePorts: string[];
205
+ } | {
206
+ id: "mcp.prompts";
207
+ title: string;
208
+ layer: "agent";
209
+ visibility: "deferred";
210
+ risk: "read";
211
+ interaction: "inspect";
212
+ description: string;
213
+ inputSchema: Readonly<Record<string, unknown>>;
214
+ aliases: string[];
215
+ capabilityTags: string[];
216
+ requiresRuntimePorts: string[];
217
+ } | {
218
+ id: "mcp.completions";
219
+ title: string;
220
+ layer: "agent";
221
+ visibility: "deferred";
222
+ risk: "read";
223
+ interaction: "inspect";
224
+ description: string;
225
+ inputSchema: Readonly<Record<string, unknown>>;
226
+ aliases: string[];
227
+ capabilityTags: string[];
228
+ requiresRuntimePorts: string[];
205
229
  } | {
206
230
  id: "lsp.query";
207
231
  title: string;
@@ -289,13 +289,51 @@ export const TOOL_BASE_CATALOG = [
289
289
  visibility: "deferred",
290
290
  risk: "read",
291
291
  interaction: "inspect",
292
- description: "List or read resources exposed by mounted MCP servers.",
292
+ description: "List resources, list resource templates, read, subscribe to, or unsubscribe from resources exposed by mounted MCP servers.",
293
293
  inputSchema: objectSchema({
294
294
  server: { type: "string" },
295
295
  uri: { type: "string" },
296
- action: { type: "string", enum: ["list", "read"] },
296
+ subscriptionId: { type: "string" },
297
+ action: { type: "string", enum: ["list", "templates", "read", "subscribe", "unsubscribe"] },
297
298
  }, ["action"]),
298
- aliases: ["list_mcp_resources", "read_mcp_resource"],
299
+ aliases: ["list_mcp_resources", "list_mcp_resource_templates", "read_mcp_resource", "subscribe_mcp_resource", "unsubscribe_mcp_resource"],
300
+ capabilityTags: ["mcp", "external", "context"],
301
+ requiresRuntimePorts: ["mcp"],
302
+ },
303
+ {
304
+ id: "mcp.prompts",
305
+ title: "Read MCP Prompts",
306
+ layer: "agent",
307
+ visibility: "deferred",
308
+ risk: "read",
309
+ interaction: "inspect",
310
+ description: "List or get prompts exposed by mounted MCP servers.",
311
+ inputSchema: objectSchema({
312
+ server: { type: "string" },
313
+ name: { type: "string" },
314
+ cursor: { type: "string" },
315
+ action: { type: "string", enum: ["list", "get"] },
316
+ arguments: { type: "object" },
317
+ }, ["action"]),
318
+ aliases: ["list_mcp_prompts", "get_mcp_prompt"],
319
+ capabilityTags: ["mcp", "external", "context"],
320
+ requiresRuntimePorts: ["mcp"],
321
+ },
322
+ {
323
+ id: "mcp.completions",
324
+ title: "Complete MCP Arguments",
325
+ layer: "agent",
326
+ visibility: "deferred",
327
+ risk: "read",
328
+ interaction: "inspect",
329
+ description: "Request completion suggestions for prompt arguments or resource template variables exposed by mounted MCP servers.",
330
+ inputSchema: objectSchema({
331
+ server: { type: "string" },
332
+ ref: { type: "object" },
333
+ argument: { type: "object" },
334
+ context: { type: "object" },
335
+ }, ["ref", "argument"]),
336
+ aliases: ["complete_mcp_argument", "complete_mcp_resource_template"],
299
337
  capabilityTags: ["mcp", "external", "context"],
300
338
  requiresRuntimePorts: ["mcp"],
301
339
  },
@@ -1,6 +1,6 @@
1
1
  export declare const MINIMAL_CODING_TOOL_IDS: readonly ["shell.run", "file.read", "file.search", "patch.apply", "plan.update", "user.ask"];
2
2
  export declare const STANDARD_AGENT_TOOL_IDS: readonly ["shell.run", "file.read", "file.search", "patch.apply", "plan.update", "user.ask", "web.search", "web.fetch", "skill.load", "mcp.use", "agent.spawn"];
3
- export declare const EXTENDED_AGENT_TOOL_IDS: readonly ["shell.run", "file.read", "file.search", "patch.apply", "plan.update", "user.ask", "web.search", "web.fetch", "skill.load", "mcp.use", "agent.spawn", "file.write", "file.edit", "agent.message", "agent.wait", "context.load", "mcp.resources", "lsp.query", "browser.use", "computer.use", "image.view", "image.generate", "audio.transcribe", "media.generate", "memory.use", "repo.inspect"];
3
+ export declare const EXTENDED_AGENT_TOOL_IDS: readonly ["shell.run", "file.read", "file.search", "patch.apply", "plan.update", "user.ask", "web.search", "web.fetch", "skill.load", "mcp.use", "agent.spawn", "file.write", "file.edit", "agent.message", "agent.wait", "context.load", "mcp.resources", "mcp.prompts", "lsp.query", "browser.use", "computer.use", "image.view", "image.generate", "audio.transcribe", "media.generate", "memory.use", "repo.inspect"];
4
4
  export declare const TOOL_BASE_PROFILES: readonly [{
5
5
  readonly name: "minimalCoding";
6
6
  readonly description: "Pi/Codex-like small coding set for models that perform best with a short familiar tool list.";
@@ -19,9 +19,9 @@ export declare const TOOL_BASE_PROFILES: readonly [{
19
19
  readonly name: "extendedAgent";
20
20
  readonly description: "Large set for high-capability runtimes; uncommon tools remain deferred until the agent asks for them.";
21
21
  readonly defaultVisibility: "deferred";
22
- readonly toolIds: readonly ["shell.run", "file.read", "file.search", "patch.apply", "plan.update", "user.ask", "web.search", "web.fetch", "skill.load", "mcp.use", "agent.spawn", "file.write", "file.edit", "agent.message", "agent.wait", "context.load", "mcp.resources", "lsp.query", "browser.use", "computer.use", "image.view", "image.generate", "audio.transcribe", "media.generate", "memory.use", "repo.inspect"];
22
+ readonly toolIds: readonly ["shell.run", "file.read", "file.search", "patch.apply", "plan.update", "user.ask", "web.search", "web.fetch", "skill.load", "mcp.use", "agent.spawn", "file.write", "file.edit", "agent.message", "agent.wait", "context.load", "mcp.resources", "mcp.prompts", "lsp.query", "browser.use", "computer.use", "image.view", "image.generate", "audio.transcribe", "media.generate", "memory.use", "repo.inspect"];
23
23
  readonly hiddenToolIds: readonly [];
24
- readonly deferredToolIds: readonly ["file.write", "file.edit", "agent.message", "agent.wait", "context.load", "mcp.resources", "lsp.query", "browser.use", "computer.use", "image.view", "image.generate", "audio.transcribe", "media.generate", "memory.use", "repo.inspect"];
24
+ readonly deferredToolIds: readonly ["file.write", "file.edit", "agent.message", "agent.wait", "context.load", "mcp.resources", "mcp.prompts", "lsp.query", "browser.use", "computer.use", "image.view", "image.generate", "audio.transcribe", "media.generate", "memory.use", "repo.inspect"];
25
25
  }, {
26
26
  readonly name: "runtimeOnly";
27
27
  readonly description: "Runtime governance ports and internal operations; never sent directly to the model.";
@@ -22,6 +22,7 @@ export const EXTENDED_AGENT_TOOL_IDS = [
22
22
  "agent.wait",
23
23
  "context.load",
24
24
  "mcp.resources",
25
+ "mcp.prompts",
25
26
  "lsp.query",
26
27
  "browser.use",
27
28
  "computer.use",
@@ -62,6 +63,7 @@ export const TOOL_BASE_PROFILES = [
62
63
  "agent.wait",
63
64
  "context.load",
64
65
  "mcp.resources",
66
+ "mcp.prompts",
65
67
  "lsp.query",
66
68
  "browser.use",
67
69
  "computer.use",
@@ -3,7 +3,7 @@ export type ToolBaseVisibility = "model" | "deferred" | "runtime" | "disabled";
3
3
  export type ToolBaseRisk = "safe" | "read" | "write" | "network" | "execute" | "dangerous";
4
4
  export type ToolBaseInteraction = "inspect" | "mutate" | "execute" | "delegate" | "ask" | "govern" | "generate";
5
5
  export type ToolBaseSchema = Readonly<Record<string, unknown>>;
6
- export type ToolBaseId = "shell.run" | "file.read" | "file.write" | "file.edit" | "file.search" | "patch.apply" | "web.search" | "web.fetch" | "plan.update" | "user.ask" | "agent.spawn" | "agent.message" | "agent.wait" | "skill.load" | "context.load" | "mcp.use" | "mcp.resources" | "lsp.query" | "browser.use" | "computer.use" | "image.view" | "image.generate" | "audio.transcribe" | "media.generate" | "memory.use" | "repo.inspect" | "approval.request" | "permission.check" | "sandbox.run" | "artifact.store" | "output.truncate" | "process.wait" | "process.kill" | "secret.resolve" | "tool.discover" | "tool.describe" | (string & {});
6
+ export type ToolBaseId = "shell.run" | "file.read" | "file.write" | "file.edit" | "file.search" | "patch.apply" | "web.search" | "web.fetch" | "plan.update" | "user.ask" | "agent.spawn" | "agent.message" | "agent.wait" | "skill.load" | "context.load" | "mcp.use" | "mcp.resources" | "mcp.prompts" | "lsp.query" | "browser.use" | "computer.use" | "image.view" | "image.generate" | "audio.transcribe" | "media.generate" | "memory.use" | "repo.inspect" | "approval.request" | "permission.check" | "sandbox.run" | "artifact.store" | "output.truncate" | "process.wait" | "process.kill" | "secret.resolve" | "tool.discover" | "tool.describe" | (string & {});
7
7
  export type ToolBaseDefinition = {
8
8
  id: ToolBaseId;
9
9
  title: string;
@@ -4,6 +4,26 @@ import type { HarnessSpec } from "@praxis-ai/praxis";
4
4
  import type { NormalizedRepoInspectorOptions } from "../config/repoInspectorOptions.js";
5
5
  import { createRepoInspectorToolSet } from "../tools/toolSet.js";
6
6
 
7
+ const repoInspectorSkillModule = praxis.skill.module({
8
+ sources: [
9
+ praxis.skill.inline([{
10
+ skillId: "repo-review.findings-first",
11
+ title: "Findings First Review",
12
+ summary: "Lead with actionable findings and put summaries after risks.",
13
+ scope: "project",
14
+ whenToUse: "Code review and regression-risk tasks",
15
+ pitfallsPreview: ["Do not bury test gaps in a summary."],
16
+ }, {
17
+ skillId: "repo-inspection.anchor-current-target",
18
+ title: "Anchor Current Target",
19
+ summary: "Restate the current repository/path/task before inspecting or editing.",
20
+ scope: "project",
21
+ whenToUse: "Long context or task-switching sessions",
22
+ pitfallsPreview: ["Do not continue a previous repository by inertia."],
23
+ }]),
24
+ ],
25
+ });
26
+
7
27
  export function createRepoInspectorHarness(options: NormalizedRepoInspectorOptions): HarnessSpec {
8
28
  return praxis.harness({
9
29
  modelRef: `model.repoInspector.${options.mode}`,
@@ -30,6 +50,9 @@ export function createRepoInspectorHarness(options: NormalizedRepoInspectorOptio
30
50
  memoryRefs: [
31
51
  "memory.example.fullstack.mpBridge.contract",
32
52
  ],
53
+ modules: {
54
+ skill: repoInspectorSkillModule,
55
+ },
33
56
  tools: praxis.tools(createRepoInspectorToolSet(options)),
34
57
  policy: praxis.policy({
35
58
  allowProviderCall: true,