@matyah00/openpi 0.1.4 → 0.2.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/package.json CHANGED
@@ -1,15 +1,19 @@
1
1
  {
2
2
  "name": "@matyah00/openpi",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
- "description": "Pi-native commands, skills, agents, and workflows.",
5
+ "description": "Comprehensive, high-performance, and safety-hardened Pi-native multi-agent orchestration package, featuring advanced workflows, damage-control rules, and developer tooling.",
6
6
  "keywords": [
7
7
  "pi-package",
8
8
  "pi-coding-agent",
9
9
  "commands",
10
10
  "skills",
11
11
  "agents",
12
- "workflows"
12
+ "workflows",
13
+ "orchestration",
14
+ "safety",
15
+ "multi-agent",
16
+ "damage-control"
13
17
  ],
14
18
  "homepage": "https://github.com/haytamAroui/OpenPi#readme",
15
19
  "repository": {
@@ -24,6 +28,7 @@
24
28
  "agents",
25
29
  "extensions",
26
30
  "prompts",
31
+ "scripts",
27
32
  "skills",
28
33
  "themes",
29
34
  "types",
@@ -35,6 +40,12 @@
35
40
  "publishConfig": {
36
41
  "access": "public"
37
42
  },
43
+ "scripts": {
44
+ "check": "npm run validate && npm run typecheck && npm run pack:check",
45
+ "pack:check": "npm pack --dry-run",
46
+ "typecheck": "tsc --noEmit",
47
+ "validate": "node scripts/validate-package.mjs"
48
+ },
38
49
  "dependencies": {
39
50
  "yaml": "^2.8.0"
40
51
  },
@@ -0,0 +1,37 @@
1
+ ---
2
+ description: Generate or update documentation with gap detection and review
3
+ category: quality
4
+ aliases:
5
+ - document
6
+ ---
7
+
8
+ Generate or update documentation for:
9
+
10
+ $ARGUMENTS
11
+
12
+ Process:
13
+
14
+ 1. Use `project_tree` to map the project structure.
15
+ 2. Use `code_search_batch` to find exports, public APIs, route definitions, and type declarations.
16
+ 3. Identify documentation gaps:
17
+ - Missing README sections (setup, usage, API, contributing)
18
+ - Undocumented public functions, classes, or endpoints
19
+ - Stale documentation that doesn't match current code
20
+ - Missing architecture or design decision records
21
+ 4. Use `spawn_agents` with `docs-writer` for detailed documentation generation when useful.
22
+ 5. Use `spawn_agents` with `reviewer` to validate accuracy of generated docs.
23
+
24
+ Rules:
25
+
26
+ - Match existing documentation style and conventions.
27
+ - Include working code examples.
28
+ - Document error cases and edge cases.
29
+ - Use concrete language, not abstract descriptions.
30
+ - Link between related sections.
31
+ - Include prerequisites and setup steps.
32
+
33
+ Output:
34
+
35
+ - Generated or updated documentation files.
36
+ - List of remaining documentation gaps.
37
+ - Review verdict on documentation accuracy.
@@ -0,0 +1,44 @@
1
+ ---
2
+ description: Plan and execute migrations with risk assessment, phased execution, and rollback strategies
3
+ category: planning
4
+ aliases:
5
+ - upgrade
6
+ ---
7
+
8
+ Plan a migration for:
9
+
10
+ $ARGUMENTS
11
+
12
+ Process:
13
+
14
+ 1. Use `env_scan` to identify the current stack and versions.
15
+ 2. Use `dependency_inventory` to audit current dependencies.
16
+ 3. Use `code_search_batch` to find all touchpoints for the migration target.
17
+ 4. Use `spawn_agents` with `migration-expert` for detailed migration analysis.
18
+ 5. If the migration is risky (data loss possible, breaking changes), use `spawn_agents` with `red-team` to challenge the plan.
19
+
20
+ Output:
21
+
22
+ ```text
23
+ Migration: {from} → {to}
24
+
25
+ Risk: low | medium | high - {why}
26
+
27
+ Current state:
28
+ - ...
29
+
30
+ Breaking changes:
31
+ 1. ...
32
+
33
+ Phases:
34
+ 1. {phase} - rollback: {strategy}
35
+ 2. ...
36
+
37
+ Validation:
38
+ - {command or check}
39
+
40
+ Point of no return:
41
+ - {phase N} — after this, rollback requires {strategy}
42
+ ```
43
+
44
+ Do not execute destructive operations. Present the plan and wait for approval.
@@ -0,0 +1,52 @@
1
+ ---
2
+ description: Performance audit with bottleneck identification and improvement prioritization
3
+ category: quality
4
+ aliases:
5
+ - performance
6
+ ---
7
+
8
+ Run a performance audit for:
9
+
10
+ $ARGUMENTS
11
+
12
+ Process:
13
+
14
+ 1. Use `env_scan` to identify the stack and build tooling.
15
+ 2. Use `project_tree` to understand project structure and identify hot paths.
16
+ 3. Use `code_search_batch` for known performance anti-patterns:
17
+ - N+1 queries, missing indexes, synchronous I/O in async code
18
+ - Large bundle imports, missing tree-shaking, barrel re-exports
19
+ - Missing memoization, inline closures in render, unstable keys
20
+ - O(n²) loops, repeated serialization, missing caching
21
+ 4. Use `spawn_agents` with `perf-auditor` for in-depth analysis when useful.
22
+ 5. Categorize findings by impact and effort.
23
+
24
+ Output:
25
+
26
+ ```text
27
+ Performance Audit: {scope}
28
+
29
+ Risk Level: low | medium | high | critical
30
+
31
+ Quick Wins (< 1 hour):
32
+ 1. file:line - issue - estimated improvement
33
+
34
+ Medium Effort (1-4 hours):
35
+ 1. file:line - issue - estimated improvement
36
+
37
+ Architecture Changes:
38
+ 1. description - estimated improvement - effort
39
+
40
+ Bundle Analysis:
41
+ - Total: ...
42
+ - Largest deps: ...
43
+
44
+ Query Analysis:
45
+ - Hot paths: ...
46
+ - N+1 patterns: ...
47
+
48
+ Recommendations:
49
+ 1. ...
50
+ ```
51
+
52
+ Do not optimize prematurely. Focus on measured or evidenced bottlenecks.
@@ -0,0 +1,53 @@
1
+ ---
2
+ description: Structured refactoring workflow with smell detection, test verification, and safe execution
3
+ category: quality
4
+ aliases:
5
+ - cleanup
6
+ ---
7
+
8
+ Refactor the following:
9
+
10
+ $ARGUMENTS
11
+
12
+ Do not change behavior. The output of the code before and after must be identical for all inputs.
13
+
14
+ Process:
15
+
16
+ 1. Use `code_search_batch` and `project_tree` to map the scope.
17
+ 2. Identify the code smell or structural problem. Name it:
18
+ - duplicate code, long method, large class, feature envy, data clump,
19
+ - shotgun surgery, divergent change, primitive obsession, dead code,
20
+ - inappropriate intimacy, message chain, speculative generality.
21
+ 3. Check for existing tests covering the target code. If tests exist, run them before refactoring.
22
+ 4. If no tests exist and the change is risky, write a characterization test first.
23
+ 5. Plan the refactoring as a series of small, independently verifiable steps.
24
+ 6. Execute one step at a time. Re-run tests after each step.
25
+ 7. If any test fails after a step, revert that step and investigate.
26
+ 8. Use `spawn_agents` with `reviewer` to verify the refactoring preserves behavior.
27
+
28
+ Output:
29
+
30
+ ```text
31
+ Refactoring: {smell} in {scope}
32
+
33
+ Before:
34
+ - Structure: ...
35
+ - Issues: ...
36
+
37
+ Steps:
38
+ 1. {step} - verified by {test or check}
39
+ 2. ...
40
+
41
+ After:
42
+ - Structure: ...
43
+ - Behavior change: NONE
44
+
45
+ Test results:
46
+ - Before: ...
47
+ - After: ...
48
+
49
+ Remaining smells:
50
+ - ...
51
+ ```
52
+
53
+ Do not combine refactoring with feature work. Refactoring is behavior-preserving only.
@@ -0,0 +1,127 @@
1
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
2
+ import { basename, join, relative, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { parse as parseYaml } from "yaml";
5
+
6
+ const root = resolve(fileURLToPath(new URL("..", import.meta.url)));
7
+ const failures = [];
8
+
9
+ function fail(message) {
10
+ failures.push(message);
11
+ }
12
+
13
+ function read(path) {
14
+ return readFileSync(join(root, path), "utf-8");
15
+ }
16
+
17
+ function walk(dir, predicate = () => true) {
18
+ const absolute = join(root, dir);
19
+ if (!existsSync(absolute)) return [];
20
+ const files = [];
21
+ for (const entry of readdirSync(absolute, { withFileTypes: true })) {
22
+ const full = join(absolute, entry.name);
23
+ if (entry.isDirectory()) files.push(...walk(relative(root, full), predicate));
24
+ else if (predicate(entry.name)) files.push(relative(root, full).replace(/\\/g, "/"));
25
+ }
26
+ return files;
27
+ }
28
+
29
+ function parseMarkdown(file) {
30
+ const raw = read(file);
31
+ const match = raw.match(/^---\s*\r?\n([\s\S]*?)\r?\n---\s*\r?\n([\s\S]*)$/);
32
+ if (!match) return { frontmatter: {}, body: raw };
33
+ const frontmatter = parseYaml(match[1]) ?? {};
34
+ if (!frontmatter || typeof frontmatter !== "object" || Array.isArray(frontmatter)) {
35
+ fail(`${file}: frontmatter must be a mapping`);
36
+ return { frontmatter: {}, body: match[2] };
37
+ }
38
+ return { frontmatter, body: match[2] };
39
+ }
40
+
41
+ for (const file of walk("extensions", (name) => name.endsWith(".ts"))) {
42
+ const content = read(file);
43
+ if (content.includes("@mariozechner/")) fail(`${file}: uses old @mariozechner namespace`);
44
+ if (content.includes("@sinclair/typebox")) fail(`${file}: uses @sinclair/typebox instead of typebox`);
45
+ if (/--append-system-prompt",\s*(state\.def|agentDef)\.systemPrompt/.test(content)) {
46
+ fail(`${file}: passes raw system prompt instead of a temp file`);
47
+ }
48
+ }
49
+
50
+ const promptNames = new Map();
51
+ for (const file of walk("prompts", (name) => name.endsWith(".md"))) {
52
+ const { frontmatter, body } = parseMarkdown(file);
53
+ const name = typeof frontmatter.name === "string" ? frontmatter.name : basename(file, ".md");
54
+ if (!body.trim()) fail(`${file}: prompt body is empty`);
55
+ if (promptNames.has(name)) fail(`${file}: duplicate prompt name "${name}" also used by ${promptNames.get(name)}`);
56
+ promptNames.set(name, file);
57
+ }
58
+
59
+ const agentNames = new Set();
60
+ for (const file of walk("agents", (name) => name.endsWith(".md"))) {
61
+ const { frontmatter, body } = parseMarkdown(file);
62
+ if (typeof frontmatter.name !== "string" || !frontmatter.name.trim()) fail(`${file}: missing agent name`);
63
+ if (typeof frontmatter.description !== "string" || !frontmatter.description.trim()) fail(`${file}: missing agent description`);
64
+ if (!body.trim()) fail(`${file}: agent body is empty`);
65
+ if (typeof frontmatter.name === "string") agentNames.add(frontmatter.name);
66
+ }
67
+
68
+ const teams = parseYaml(read("agents/teams.yaml")) ?? {};
69
+ for (const [team, members] of Object.entries(teams)) {
70
+ if (!Array.isArray(members)) {
71
+ fail(`agents/teams.yaml: ${team} must be a list`);
72
+ continue;
73
+ }
74
+ for (const member of members) {
75
+ if (!agentNames.has(member)) fail(`agents/teams.yaml: ${team} references unknown agent ${member}`);
76
+ }
77
+ }
78
+
79
+ const chains = parseYaml(read("agents/agent-chain.yaml")) ?? {};
80
+ for (const [chainName, chain] of Object.entries(chains)) {
81
+ if (!chain || typeof chain !== "object" || Array.isArray(chain) || !Array.isArray(chain.steps)) {
82
+ fail(`agents/agent-chain.yaml: ${chainName} must have steps`);
83
+ continue;
84
+ }
85
+ for (const [index, step] of chain.steps.entries()) {
86
+ if (!step || typeof step !== "object" || Array.isArray(step)) {
87
+ fail(`agents/agent-chain.yaml: ${chainName} step ${index + 1} must be a mapping`);
88
+ continue;
89
+ }
90
+ if (!agentNames.has(step.agent)) fail(`agents/agent-chain.yaml: ${chainName} references unknown agent ${step.agent}`);
91
+ if (typeof step.prompt !== "string" || !step.prompt.trim()) {
92
+ fail(`agents/agent-chain.yaml: ${chainName} step ${index + 1} missing prompt`);
93
+ } else if (!step.prompt.includes("$INPUT") && !step.prompt.includes("$ORIGINAL") && !/\$STEP_\d+/.test(step.prompt)) {
94
+ fail(`agents/agent-chain.yaml: ${chainName} step ${index + 1} prompt must contain either $INPUT, $ORIGINAL or $STEP_N`);
95
+ }
96
+ }
97
+ }
98
+
99
+ // 2. Validate skill directories
100
+ const skillsAbsolute = join(root, "skills");
101
+ if (existsSync(skillsAbsolute)) {
102
+ for (const entry of readdirSync(skillsAbsolute, { withFileTypes: true })) {
103
+ if (entry.isDirectory()) {
104
+ const skillFile = join(skillsAbsolute, entry.name, "SKILL.md");
105
+ if (!existsSync(skillFile)) {
106
+ fail(`skills/${entry.name}: missing SKILL.md`);
107
+ }
108
+ }
109
+ }
110
+ }
111
+
112
+ // 3. Validate theme JSON files
113
+ for (const file of walk("themes", (name) => name.endsWith(".json"))) {
114
+ try {
115
+ JSON.parse(read(file));
116
+ } catch (err) {
117
+ fail(`${file}: invalid JSON theme file: ${err.message}`);
118
+ }
119
+ }
120
+
121
+ if (failures.length) {
122
+
123
+ console.error(failures.map((item) => `- ${item}`).join("\n"));
124
+ process.exit(1);
125
+ }
126
+
127
+ console.log("openpi package validation passed");
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: perf-auditor
3
+ description: Use when diagnosing performance issues, optimizing bundle size, fixing slow queries, reducing memory usage, or auditing hot paths.
4
+ ---
5
+
6
+ # Performance Auditor
7
+
8
+ Focus on measured or evidenced bottlenecks. Do not optimize prematurely.
9
+
10
+ ## Frontend Performance
11
+
12
+ Check for:
13
+ - Large bundle imports (`import _ from 'lodash'` instead of `import get from 'lodash/get'`)
14
+ - Barrel file re-exports that prevent tree-shaking
15
+ - Missing `React.memo`, `useMemo`, `useCallback` on expensive renders
16
+ - Inline object/function props causing unnecessary re-renders
17
+ - Unoptimized images, missing lazy loading
18
+ - Blocking synchronous scripts in `<head>`
19
+ - Layout thrashing from synchronous DOM read/write cycles
20
+
21
+ ## Backend Performance
22
+
23
+ Check for:
24
+ - N+1 query patterns in ORM usage (loop with `.find()` or `.get()`)
25
+ - Missing database indexes on filtered/sorted columns
26
+ - Synchronous file I/O in async request handlers
27
+ - Unclosed database connections or missing connection pooling
28
+ - CPU-bound work blocking the event loop
29
+ - Unbounded in-memory caches
30
+ - Missing pagination on list endpoints
31
+
32
+ ## General
33
+
34
+ Check for:
35
+ - O(n²) or worse algorithmic complexity in hot paths
36
+ - Repeated JSON serialization/deserialization
37
+ - Missing HTTP caching headers
38
+ - Unnecessary network roundtrips
39
+ - Cold start overhead from eager loading
40
+
41
+ ## Tools
42
+
43
+ Use `code_search_batch` with patterns:
44
+ - `\.find\(`, `\.findOne\(`, `\.get\(` inside loops for N+1
45
+ - `import .* from ['"]lodash['"]` for barrel imports
46
+ - `fs\.readFileSync`, `fs\.writeFileSync` for sync I/O
47
+ - `JSON\.parse.*JSON\.stringify` for repeated serialization
48
+
49
+ Report findings with `file:line`, estimated impact, and effort to fix.
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: refactor-guide
3
+ description: Use when refactoring code, cleaning up technical debt, removing code smells, extracting modules, or restructuring without changing behavior.
4
+ ---
5
+
6
+ # Refactor Guide
7
+
8
+ Refactoring preserves behavior. Never combine refactoring with feature work.
9
+
10
+ ## Before Refactoring
11
+
12
+ 1. Identify the code smell by name:
13
+ - Duplicate code, long method, large class, feature envy, data clump,
14
+ - shotgun surgery, divergent change, primitive obsession, dead code,
15
+ - inappropriate intimacy, message chain, speculative generality.
16
+ 2. Find existing tests covering the target. Run them. They must pass.
17
+ 3. If no tests exist and the change is risky, write a characterization test first.
18
+
19
+ ## During Refactoring
20
+
21
+ 1. Plan as a series of small, independently verifiable steps.
22
+ 2. Execute one step at a time.
23
+ 3. Re-run relevant tests after each step.
24
+ 4. If any test fails, revert that step and investigate.
25
+ 5. Do not refactor and add features in the same change.
26
+
27
+ ## After Refactoring
28
+
29
+ 1. Run the full relevant test suite.
30
+ 2. Use `ghost_test_scan` before trusting green tests.
31
+ 3. Verify no behavior change with concrete before/after evidence.
32
+ 4. Use `spawn_agents` with `reviewer` to validate the diff preserves behavior.
33
+
34
+ ## Anti-Patterns to Avoid
35
+
36
+ - Refactoring without tests as a safety net.
37
+ - "While I'm in here" feature additions.
38
+ - Speculative abstraction (don't extract what you don't need yet).
39
+ - Renaming for style without consensus.
package/tsconfig.json CHANGED
@@ -6,7 +6,8 @@
6
6
  "allowImportingTsExtensions": true,
7
7
  "noEmit": true,
8
8
  "skipLibCheck": true,
9
- "strict": false
9
+ "strict": true,
10
+ "noImplicitAny": false
10
11
  },
11
12
  "include": [
12
13
  "extensions/**/*.ts",
@@ -1,11 +1,3 @@
1
- declare module "@mariozechner/pi-coding-agent" {
2
- export type ExtensionContext = any;
3
- export type ExtensionAPI = any;
4
- export const DynamicBorder: any;
5
- export function isToolCallEventType(...args: any[]): boolean;
6
- export function getMarkdownTheme(...args: any[]): any;
7
- }
8
-
9
1
  declare module "@earendil-works/pi-coding-agent" {
10
2
  export type ExtensionContext = any;
11
3
  export type ExtensionAPI = any;
@@ -17,36 +9,6 @@ declare module "@earendil-works/pi-coding-agent" {
17
9
  export function withFileMutationQueue<T = any>(...args: any[]): Promise<T>;
18
10
  }
19
11
 
20
- declare module "@mariozechner/pi-tui" {
21
- export class Text {
22
- constructor(...args: any[]);
23
- setText(...args: any[]): any;
24
- render(...args: any[]): any;
25
- invalidate(...args: any[]): any;
26
- }
27
- export class Box {
28
- constructor(...args: any[]);
29
- }
30
- export class Markdown {
31
- constructor(...args: any[]);
32
- }
33
- export class Container {
34
- constructor(...args: any[]);
35
- addChild(...args: any[]): any;
36
- render(...args: any[]): any;
37
- invalidate(...args: any[]): any;
38
- }
39
- export class Spacer {
40
- constructor(...args: any[]);
41
- }
42
- export type AutocompleteItem = any;
43
- export const Key: any;
44
- export function matchesKey(...args: any[]): any;
45
- export function truncateToWidth(...args: any[]): any;
46
- export function visibleWidth(...args: any[]): any;
47
- export function getMarkdownTheme(...args: any[]): any;
48
- }
49
-
50
12
  declare module "@earendil-works/pi-tui" {
51
13
  export class Text {
52
14
  constructor(...args: any[]);
@@ -77,16 +39,6 @@ declare module "@earendil-works/pi-tui" {
77
39
  export function getMarkdownTheme(...args: any[]): any;
78
40
  }
79
41
 
80
- declare module "@sinclair/typebox" {
81
- export const Type: any;
82
- }
83
-
84
- declare module "@mariozechner/pi-ai" {
85
- export type AssistantMessage = any;
86
- export type Message = any;
87
- export function StringEnum(...args: any[]): any;
88
- }
89
-
90
42
  declare module "@earendil-works/pi-ai" {
91
43
  export type AssistantMessage = any;
92
44
  export type Message = any;