@rmrdeveloper/sideroom-pi 8.0.0 → 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
- const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../..');
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 (input.offset !== undefined || input.limit !== undefined) {
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(state, event.input.path);
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 guidePath of new Set(Object.values(LANGUAGE_GUIDE_BY_EXTENSION))) {
96
- if (normalizedPath === normalizePath(guidePath)) {
97
- state.languageGuidesRead.add(guidePath);
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 edit.`;
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
- const extension = Object.keys(LANGUAGE_GUIDE_BY_EXTENSION).find((candidate) =>
127
- normalizedPath.endsWith(candidate),
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
- export const GUIDELINES_REMINDER = `${GUIDELINES_REMINDER_HEADING}
5
- Before the first write or edit in each agent run, use the read tool without offset or limit on the absolute SKILL.md path shown for sideroom-guidelines in Available Skills.
6
- For .java, .php, .ts/.tsx, .py, .go, or .rs targets, also fully read exactly the matching guide under that skill's references/languages/ directory.
7
- The extension blocks write/edit until those exact full-file reads succeed. Do not bypass the gate with bash or another mutation tool.
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 LANGUAGE_GUIDE_FILES = [
11
- 'go.md',
12
- 'java.md',
13
- 'php-laravel.md',
14
- 'python.md',
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rmrdeveloper/sideroom-pi",
3
- "version": "8.0.0",
3
+ "version": "8.0.2",
4
4
  "description": "A global Pi package with a questionnaire, work board, edited-file view, and coding guidelines for parent agents.",
5
5
  "type": "module",
6
6
  "files": [
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: sideroom-domain-modeling
3
- description: "Trigger: ubiquitous language, domain term, CONTEXT.md, ADR, vague word, naming conflict. Sharpen the project's domain language while designing: challenge vague terms, split overloaded ones, and write the settled vocabulary into the repo."
3
+ description: "Resolve domain-language conflicts and naming decisions. Use when terms are ambiguous, overloaded, or used inconsistently; when deciding what belongs in CONTEXT.md; or when a domain choice may need an ADR. Use for one or a few terms, not for simply reading CONTEXT.md, scanning an entire repository, or reshaping modules."
4
4
  license: MIT
5
5
  metadata:
6
6
  author: RMRdeveloper
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: sideroom-domain-scaffold
3
- description: "Trigger: document my repo, scaffold CONTEXT.md, brownfield glossary, survey domain. Read the central domain code as source of truth and build or complete CONTEXT.md without interviewing anyone; conflicting terms are collected and grilled once, at the end."
3
+ description: "Build or complete a code-first CONTEXT.md for a repository with missing or thin domain vocabulary. Use when the user asks to document or survey the repo, scaffold a brownfield glossary, or derive domain terms from central business code. Do not use for resolving one naming conflict or conducting an interactive design interview."
4
4
  license: MIT
5
5
  metadata:
6
6
  author: RMRdeveloper
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: sideroom-grill
3
- description: "Trigger: fuzzy plan, design review, grilling, CONTEXT.md, ADR, domain language. Interview the user in rounds until you share one understanding, then write the vocabulary and the hard decisions into the repo."
3
+ description: "Interview the user in rounds to resolve a fuzzy plan, design decision, or domain-language conflict before implementation. Use when the user asks to be grilled, wants clarifying questions, or says the plan or terms are not settled. Do not use for a code-first repository scan or a simple glossary lookup."
4
4
  license: MIT
5
5
  metadata:
6
6
  author: RMRdeveloper
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: sideroom-guidelines
3
- description: "Trigger: write, edit, coding, Java, Laravel, TypeScript, Python, Go, Rust. Apply Sideroom coding principles before changing code."
3
+ description: "Apply Sideroom's mandatory coding workflow before implementing, refactoring, or fixing Java, Laravel/PHP, TypeScript/TSX, Python, Go, or Rust code. Load this skill and the exact language guide before mutation. Do not use for unrelated prose or domain-only discussions."
4
4
  license: MIT
5
5
  metadata:
6
6
  author: RMRdeveloper