proteum 2.5.23 → 2.5.24
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/common/dev/inspection.ts +14 -5
- package/common/dev/mcpPayloads.ts +6 -5
- package/docs/agent-routing.md +1 -1
- package/package.json +1 -1
- package/tests/inspection.test.cjs +19 -1
- package/tests/mcp.test.cjs +17 -0
package/common/dev/inspection.ts
CHANGED
|
@@ -780,14 +780,23 @@ const resolveGuidance = ({
|
|
|
780
780
|
manifest: TProteumManifest;
|
|
781
781
|
ownerFilepath?: string;
|
|
782
782
|
}) => {
|
|
783
|
-
// `agentInstructions: false`: the project owns one hand-written
|
|
784
|
-
// copies, so every guidance slot points at it instead of Proteum's bundled fallbacks.
|
|
783
|
+
// `agentInstructions: false`: the project owns one hand-written instruction file and deleted the
|
|
784
|
+
// routed copies, so every guidance slot points at it instead of Proteum's bundled fallbacks.
|
|
785
|
+
// Claude Code reads CLAUDE.md when it exists and AGENTS.md otherwise; follow the same order.
|
|
785
786
|
if (manifest.app.setup.agentInstructions === false) {
|
|
786
|
-
const
|
|
787
|
+
const claudeFile = resolveGuidanceFile({
|
|
787
788
|
appRoot: manifest.app.root,
|
|
788
|
-
fallbackFilepath:
|
|
789
|
+
fallbackFilepath: '',
|
|
789
790
|
relativePath: 'CLAUDE.md',
|
|
790
|
-
})
|
|
791
|
+
});
|
|
792
|
+
const claudeInstructions =
|
|
793
|
+
claudeFile.warning === undefined
|
|
794
|
+
? claudeFile.filepath
|
|
795
|
+
: resolveGuidanceFile({
|
|
796
|
+
appRoot: manifest.app.root,
|
|
797
|
+
fallbackFilepath: joinPath(manifest.app.root, 'AGENTS.md'),
|
|
798
|
+
relativePath: 'AGENTS.md',
|
|
799
|
+
}).filepath;
|
|
791
800
|
|
|
792
801
|
return {
|
|
793
802
|
guidance: {
|
|
@@ -940,12 +940,13 @@ export const resolveInstructionRouting = ({
|
|
|
940
940
|
const selected = new Map<string, ReturnType<typeof createSelectedInstruction>>();
|
|
941
941
|
const readWhen: Array<{ file?: string; when: string }> = [];
|
|
942
942
|
|
|
943
|
-
// `agentInstructions: false`: the routed
|
|
943
|
+
// `agentInstructions: false`: the routed copies no longer exist; route to the hand-owned file the
|
|
944
|
+
// agent actually loads (Claude Code reads CLAUDE.md when it exists and AGENTS.md otherwise).
|
|
944
945
|
if (!readsProteumManagedInstructions(appRoot)) {
|
|
945
|
-
const
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
946
|
+
const ownedFile = ['CLAUDE.md', 'AGENTS.md']
|
|
947
|
+
.map((relativeFilepath) => resolveDocumentFile({ appRoot, repoRoot, relativeFilepath }))
|
|
948
|
+
.find((filepath) => filepath !== undefined && fileExists(filepath));
|
|
949
|
+
if (ownedFile) selected.set(ownedFile, createSelectedInstruction(ownedFile, 'Project-owned agent instructions.'));
|
|
949
950
|
const selectedFiles = [...selected.values()];
|
|
950
951
|
return createMcpPayload({
|
|
951
952
|
summary: `${selectedFiles.length} instruction files selected for ${normalizedQuery || 'current app'}`,
|
package/docs/agent-routing.md
CHANGED
|
@@ -141,4 +141,4 @@ The result confirms the intended routing:
|
|
|
141
141
|
|
|
142
142
|
## Hand-Owned Instructions
|
|
143
143
|
|
|
144
|
-
A project that writes its own agent instructions sets `agentInstructions: false` in each app's `proteum.config.ts`. Proteum then never writes `AGENTS.md`, `CLAUDE.md` or the routed instruction copies for that app: `proteum dev` skips the sync, `proteum configure agents` refuses to run, and a monorepo root is managed only when no app opted out. MCP `workflow_start` and `instructions_resolve` route such apps to their `CLAUDE.md`, and orientation guidance points there instead of Proteum's bundled fallbacks.
|
|
144
|
+
A project that writes its own agent instructions sets `agentInstructions: false` in each app's `proteum.config.ts`. Proteum then never writes `AGENTS.md`, `CLAUDE.md` or the routed instruction copies for that app: `proteum dev` skips the sync, `proteum configure agents` refuses to run, and a monorepo root is managed only when no app opted out. MCP `workflow_start` and `instructions_resolve` route such apps to their hand-owned instruction file (`CLAUDE.md` when it exists, else `AGENTS.md`, the order Claude Code reads them in), and orientation guidance points there instead of Proteum's bundled fallbacks.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "proteum",
|
|
3
3
|
"description": "LLM-first Opinionated Typescript Framework for web applications.",
|
|
4
|
-
"version": "2.5.
|
|
4
|
+
"version": "2.5.24",
|
|
5
5
|
"author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
|
|
6
6
|
"repository": "git://github.com/gaetanlegac/proteum.git",
|
|
7
7
|
"license": "MIT",
|
|
@@ -6,7 +6,7 @@ process.env.TS_NODE_PROJECT = path.join(coreRoot, 'cli', 'tsconfig.json');
|
|
|
6
6
|
process.env.TS_NODE_TRANSPILE_ONLY = '1';
|
|
7
7
|
require('ts-node/register/transpile-only');
|
|
8
8
|
|
|
9
|
-
const { explainOwner } = require('../common/dev/inspection.ts');
|
|
9
|
+
const { buildOrientationResponse, explainOwner } = require('../common/dev/inspection.ts');
|
|
10
10
|
|
|
11
11
|
const createRoute = (routePath, filepath) => ({
|
|
12
12
|
chunkFilepath: filepath,
|
|
@@ -64,3 +64,21 @@ test('root owner lookup returns only the literal root route when present', () =>
|
|
|
64
64
|
assert.equal(matches.length, 1);
|
|
65
65
|
assert.equal(matches[0].label, '/');
|
|
66
66
|
});
|
|
67
|
+
|
|
68
|
+
test('orientation guidance of an opted-out app points at its hand-owned instruction file', () => {
|
|
69
|
+
const fs = require('node:fs');
|
|
70
|
+
const os = require('node:os');
|
|
71
|
+
const appRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'proteum-owned-guidance-'));
|
|
72
|
+
fs.mkdirSync(path.join(appRoot, '.git'));
|
|
73
|
+
fs.writeFileSync(path.join(appRoot, 'AGENTS.md'), '# Owned\n');
|
|
74
|
+
const manifest = createManifest([]);
|
|
75
|
+
manifest.app = { coreRoot, root: appRoot, identity: { identifier: 'OwnedApp', name: 'Owned App' }, setup: { agentInstructions: false } };
|
|
76
|
+
|
|
77
|
+
const agentsOnly = buildOrientationResponse(manifest, '/').guidance;
|
|
78
|
+
assert.equal(agentsOnly.agents, path.join(appRoot, 'AGENTS.md'));
|
|
79
|
+
assert.equal(agentsOnly.documentation, path.join(appRoot, 'AGENTS.md'));
|
|
80
|
+
assert.deepEqual(agentsOnly.areaAgents, []);
|
|
81
|
+
|
|
82
|
+
fs.writeFileSync(path.join(appRoot, 'CLAUDE.md'), '# Owned for Claude\n');
|
|
83
|
+
assert.equal(buildOrientationResponse(manifest, '/').guidance.agents, path.join(appRoot, 'CLAUDE.md'));
|
|
84
|
+
});
|
package/tests/mcp.test.cjs
CHANGED
|
@@ -156,6 +156,23 @@ const writeFreshCopyFixture = (appRoot, manifestOverrides = {}) => {
|
|
|
156
156
|
writeFile(path.join(appRoot, '.proteum', 'manifest.json'), JSON.stringify(createManifest(appRoot, manifestOverrides), null, 2));
|
|
157
157
|
};
|
|
158
158
|
|
|
159
|
+
test('instruction routing sends an opted-out app to its hand-owned instruction file', () => {
|
|
160
|
+
const appRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'proteum-mcp-owned-'));
|
|
161
|
+
|
|
162
|
+
writeFile(path.join(appRoot, 'proteum.config.ts'), 'export default { agentInstructions: false };\n');
|
|
163
|
+
writeFile(path.join(appRoot, 'AGENTS.md'), '# Owned\n');
|
|
164
|
+
writeFile(path.join(appRoot, 'client', 'AGENTS.md'), '# Stale routed copy\n');
|
|
165
|
+
|
|
166
|
+
const agentsOnly = resolveInstructionRouting({ appRoot, query: 'client/pages/domain.tsx' });
|
|
167
|
+
assert.deepEqual(agentsOnly.data.selected.map((entry) => path.relative(appRoot, entry.file)), ['AGENTS.md']);
|
|
168
|
+
assert.deepEqual(agentsOnly.data.readWhen, []);
|
|
169
|
+
|
|
170
|
+
// Claude Code reads CLAUDE.md first when both exist, so routing follows it.
|
|
171
|
+
writeFile(path.join(appRoot, 'CLAUDE.md'), '# Owned for Claude\n');
|
|
172
|
+
const withClaude = resolveInstructionRouting({ appRoot, query: 'client/pages/domain.tsx' });
|
|
173
|
+
assert.deepEqual(withClaude.data.selected.map((entry) => path.relative(appRoot, entry.file)), ['CLAUDE.md']);
|
|
174
|
+
});
|
|
175
|
+
|
|
159
176
|
test('instruction routing returns compact selected files for a page query', () => {
|
|
160
177
|
const appRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'proteum-mcp-app-'));
|
|
161
178
|
|