@rmrdeveloper/sideroom-pi 8.0.1 → 8.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { dirname, join, resolve } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
|
|
4
|
+
const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../..');
|
|
5
|
+
const LANGUAGE_GUIDE_DIRECTORY = join(
|
|
6
|
+
PACKAGE_ROOT,
|
|
7
|
+
'skills/sideroom-guidelines/references/languages',
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
export const GUIDELINE_SKILL_PATH = join(
|
|
11
|
+
PACKAGE_ROOT,
|
|
12
|
+
'skills/sideroom-guidelines/SKILL.md',
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
export interface LanguageGuide {
|
|
16
|
+
readonly extensions: readonly string[];
|
|
17
|
+
readonly fileName: string;
|
|
18
|
+
readonly path: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const LANGUAGE_GUIDES: readonly LanguageGuide[] = [
|
|
22
|
+
languageGuide('go.md', ['.go']),
|
|
23
|
+
languageGuide('java.md', ['.java']),
|
|
24
|
+
languageGuide('php-laravel.md', ['.php']),
|
|
25
|
+
languageGuide('python.md', ['.py']),
|
|
26
|
+
languageGuide('rust.md', ['.rs']),
|
|
27
|
+
languageGuide('typescript.md', ['.ts', '.tsx']),
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
export const LANGUAGE_GUIDE_FILES: readonly string[] = LANGUAGE_GUIDES.map(
|
|
31
|
+
({ fileName }) => fileName,
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
export const LANGUAGE_TARGET_LABELS: readonly string[] = LANGUAGE_GUIDES.map(
|
|
35
|
+
({ extensions }) => extensions.join('/'),
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
function languageGuide(
|
|
39
|
+
fileName: string,
|
|
40
|
+
extensions: readonly string[],
|
|
41
|
+
): LanguageGuide {
|
|
42
|
+
return {
|
|
43
|
+
extensions,
|
|
44
|
+
fileName,
|
|
45
|
+
path: join(LANGUAGE_GUIDE_DIRECTORY, fileName),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -1,29 +1,11 @@
|
|
|
1
|
-
import { dirname, join, resolve } from 'node:path';
|
|
2
|
-
import { fileURLToPath } from 'node:url';
|
|
3
1
|
import {
|
|
4
2
|
type ExtensionAPI,
|
|
5
3
|
isReadToolResult,
|
|
6
4
|
isToolCallEventType,
|
|
7
5
|
} from '@earendil-works/pi-coding-agent';
|
|
6
|
+
import { GUIDELINE_SKILL_PATH, LANGUAGE_GUIDES } from './catalog.ts';
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
export const GUIDELINE_SKILL_PATH = join(
|
|
11
|
-
PACKAGE_ROOT,
|
|
12
|
-
'skills/sideroom-guidelines/SKILL.md',
|
|
13
|
-
);
|
|
14
|
-
const LANGUAGE_GUIDE_DIRECTORY = join(
|
|
15
|
-
PACKAGE_ROOT,
|
|
16
|
-
'skills/sideroom-guidelines/references/languages',
|
|
17
|
-
);
|
|
18
|
-
const LANGUAGE_GUIDE_BY_EXTENSION: Readonly<Record<string, string>> = {
|
|
19
|
-
'.go': join(LANGUAGE_GUIDE_DIRECTORY, 'go.md'),
|
|
20
|
-
'.java': join(LANGUAGE_GUIDE_DIRECTORY, 'java.md'),
|
|
21
|
-
'.php': join(LANGUAGE_GUIDE_DIRECTORY, 'php-laravel.md'),
|
|
22
|
-
'.py': join(LANGUAGE_GUIDE_DIRECTORY, 'python.md'),
|
|
23
|
-
'.rs': join(LANGUAGE_GUIDE_DIRECTORY, 'rust.md'),
|
|
24
|
-
'.ts': join(LANGUAGE_GUIDE_DIRECTORY, 'typescript.md'),
|
|
25
|
-
'.tsx': join(LANGUAGE_GUIDE_DIRECTORY, 'typescript.md'),
|
|
26
|
-
};
|
|
8
|
+
export { GUIDELINE_SKILL_PATH } from './catalog.ts';
|
|
27
9
|
|
|
28
10
|
interface ReadInput {
|
|
29
11
|
readonly path: string;
|
|
@@ -56,7 +38,11 @@ export function registerGuidelineGuard(
|
|
|
56
38
|
|
|
57
39
|
// SAFETY: Pi validates built-in read arguments before emitting tool_result.
|
|
58
40
|
const input = event.input as unknown as ReadInput;
|
|
59
|
-
if (
|
|
41
|
+
if (
|
|
42
|
+
input.offset !== undefined ||
|
|
43
|
+
input.limit !== undefined ||
|
|
44
|
+
event.details?.truncation?.truncated === true
|
|
45
|
+
) {
|
|
60
46
|
return;
|
|
61
47
|
}
|
|
62
48
|
recordGuidelineRead(state, input.path);
|
|
@@ -70,7 +56,11 @@ export function registerGuidelineGuard(
|
|
|
70
56
|
return;
|
|
71
57
|
}
|
|
72
58
|
|
|
73
|
-
const reason = mutationBlockReason(
|
|
59
|
+
const reason = mutationBlockReason(
|
|
60
|
+
state,
|
|
61
|
+
event.input.path,
|
|
62
|
+
pi.getActiveTools().includes('read'),
|
|
63
|
+
);
|
|
74
64
|
if (reason === undefined) {
|
|
75
65
|
return;
|
|
76
66
|
}
|
|
@@ -92,9 +82,9 @@ export function recordGuidelineRead(
|
|
|
92
82
|
return;
|
|
93
83
|
}
|
|
94
84
|
|
|
95
|
-
for (const
|
|
96
|
-
if (normalizedPath === normalizePath(
|
|
97
|
-
state.languageGuidesRead.add(
|
|
85
|
+
for (const guide of LANGUAGE_GUIDES) {
|
|
86
|
+
if (normalizedPath === normalizePath(guide.path)) {
|
|
87
|
+
state.languageGuidesRead.add(guide.path);
|
|
98
88
|
return;
|
|
99
89
|
}
|
|
100
90
|
}
|
|
@@ -103,6 +93,7 @@ export function recordGuidelineRead(
|
|
|
103
93
|
export function mutationBlockReason(
|
|
104
94
|
state: GuidelineReadState,
|
|
105
95
|
targetPath: string,
|
|
96
|
+
readToolAvailable = true,
|
|
106
97
|
): string | undefined {
|
|
107
98
|
const requiredPaths: string[] = [];
|
|
108
99
|
if (!state.skillRead) {
|
|
@@ -117,18 +108,18 @@ export function mutationBlockReason(
|
|
|
117
108
|
if (requiredPaths.length === 0) {
|
|
118
109
|
return undefined;
|
|
119
110
|
}
|
|
111
|
+
if (!readToolAvailable) {
|
|
112
|
+
return `Blocked ${targetPath}: the read tool is inactive, so the guidelines gate cannot be satisfied. Enable read, then read ${requiredPaths.join(' and ')} before retrying the mutation.`;
|
|
113
|
+
}
|
|
120
114
|
|
|
121
|
-
return `Blocked ${targetPath}: read ${requiredPaths.join(' and ')} with the read tool in this agent run, then retry the
|
|
115
|
+
return `Blocked ${targetPath}: read ${requiredPaths.join(' and ')} with the read tool in this agent run, then retry the mutation.`;
|
|
122
116
|
}
|
|
123
117
|
|
|
124
118
|
function languageGuideFor(path: string): string | undefined {
|
|
125
119
|
const normalizedPath = normalizePath(path).toLowerCase();
|
|
126
|
-
|
|
127
|
-
normalizedPath.endsWith(
|
|
128
|
-
);
|
|
129
|
-
return extension === undefined
|
|
130
|
-
? undefined
|
|
131
|
-
: LANGUAGE_GUIDE_BY_EXTENSION[extension];
|
|
120
|
+
return LANGUAGE_GUIDES.find(({ extensions }) =>
|
|
121
|
+
extensions.some((extension) => normalizedPath.endsWith(extension)),
|
|
122
|
+
)?.path;
|
|
132
123
|
}
|
|
133
124
|
|
|
134
125
|
function normalizePath(path: string): string {
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
+
import { GUIDELINE_SKILL_PATH, LANGUAGE_GUIDES } from './catalog.ts';
|
|
2
|
+
|
|
3
|
+
export { LANGUAGE_GUIDE_FILES } from './catalog.ts';
|
|
4
|
+
|
|
1
5
|
export const GUIDELINES_REMINDER_HEADING =
|
|
2
6
|
'Sideroom coding guidelines (always-on reminder):';
|
|
3
7
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Before finishing, review changed code against the loaded guide and run the relevant formatter, linter, type checks, and tests.`;
|
|
8
|
+
const LANGUAGE_GUIDE_REMINDERS = LANGUAGE_GUIDES.map(
|
|
9
|
+
({ extensions, path }) =>
|
|
10
|
+
`If a file you will write or edit ends in ${extensions.join(' or ')}, use the read tool without offset or limit to load the exact matching guide at ${path} in full.`,
|
|
11
|
+
).join('\n');
|
|
9
12
|
|
|
10
|
-
export const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
'rust.md',
|
|
16
|
-
'typescript.md',
|
|
17
|
-
] as const;
|
|
13
|
+
export const GUIDELINES_REMINDER = `${GUIDELINES_REMINDER_HEADING}
|
|
14
|
+
Before the first write or edit in each agent run, use the read tool without offset or limit to load ${GUIDELINE_SKILL_PATH} in full.
|
|
15
|
+
${LANGUAGE_GUIDE_REMINDERS}
|
|
16
|
+
A required read counts only when it succeeds without truncation. Until all required reads succeed, do not call write or edit and do not mutate files through bash or another tool; the extension blocks those mutations.
|
|
17
|
+
After changing files, review the code against the loaded guide and run the relevant formatter, linter, type checks, and tests.`;
|
|
18
18
|
|
|
19
19
|
export function appendGuidelinesReminder(systemPrompt: string): string {
|
|
20
20
|
if (systemPrompt.includes(GUIDELINES_REMINDER_HEADING)) {
|
package/package.json
CHANGED