一键导入
typescript
TypeScript development conventions. Covers strict typing, async patterns, error handling, Node.js API usage, and testing with node:test.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
TypeScript development conventions. Covers strict typing, async patterns, error handling, Node.js API usage, and testing with node:test.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Git conventions — conventional commits, semantic versioning, branch naming, tagging, changelogs, and release workflow. Use when committing, branching, tagging, or managing releases.
Python development guidance. Covers project setup (pyproject.toml, src/ layout), testing (pytest), linting (ruff), type checking (mypy), packaging, venv management, and CI/CD patterns. Use when creating, modifying, or debugging Python code.
Rust development guidance. Covers project setup, testing, clippy, rustfmt, and CI/CD patterns. Use when creating, modifying, or debugging Rust code.
Unified visual style guide. Defines the Alpharius color system, typography, spacing, and semantic palette shared across pi TUI theme, Excalidraw diagrams, D2 diagrams, and generated images. Use when creating any visual output to ensure consistency.
OpenSpec lifecycle for spec-driven development. Use when proposing changes, writing Given/When/Then specs, generating tasks, verifying implementations, or archiving completed changes. Commands /opsx:propose, /opsx:spec, /opsx:ff, /opsx:status, /opsx:verify, /opsx:archive.
Security checklist for code review and implementation. Covers input escaping, injection prevention, path traversal, process safety, dependency integrity, and secrets management. Load when working on user-facing code, template rendering, or process spawning.
| name | typescript |
| description | TypeScript development conventions. Covers strict typing, async patterns, error handling, Node.js API usage, and testing with node:test. |
Conventions for TypeScript code in Omegon and related projects.
any as a type annotation. Use unknown and narrow, or define a proper interface.interface over type for object shapes (better error messages, extensibility).as const assertions for literal arrays used as union sources.import type { Foo } from "./bar.js" — keeps runtime imports clean.// ❌ Bad
const data: any = await resp.json();
function process(items: any[]) { ... }
// ✅ Good
interface ApiResponse { data: Model[]; total: number; }
const data: ApiResponse = await resp.json();
function process(items: readonly Model[]) { ... }
async unless they await// ❌ Unnecessarily async — wraps return value in an extra promise
const text = async (msg: string) => ({ content: msg });
// ✅ Sync function returns plain object
const text = (msg: string) => ({ content: msg });
.then(r => r) — it's a no-op identity transform// ❌ Pointless promise chain
resolve(text("done").then(r => r));
// ✅ Direct
resolve(text("done"));
new Promise() when async/await suffices// ❌ Promise constructor anti-pattern
function doWork(): Promise<string> {
return new Promise((resolve) => {
someCallback((result) => resolve(result));
});
}
// ✅ Use promisify or async/await when possible
import { promisify } from "node:util";
const doWork = promisify(someCallback);
new Promise() is correct for wrapping event-emitter APIs// ✅ Correct use — child process exit is event-based, not promise-based
function runCommand(cmd: string): Promise<number> {
return new Promise((resolve) => {
const child = spawn("sh", ["-c", cmd]);
child.on("exit", (code) => resolve(code ?? 1));
child.on("error", () => resolve(1));
});
}
catch with typed narrowing, not catch (e: any).// ❌ Swallowed error
try { await riskyOp(); } catch { }
// ✅ Intentional ignore with comment
try { await riskyOp(); } catch { /* expected: file may not exist */ }
// ✅ Error narrowing
try {
await riskyOp();
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
return { error: message };
}
node: prefix for built-in modules// ❌
import { readFileSync } from "fs";
// ✅
import { readFileSync } from "node:fs";
execSync only for quick checks, never for long-running operations// ✅ Quick binary check
function hasBinary(name: string): boolean {
try { execSync(`which ${name}`, { stdio: "ignore" }); return true; }
catch { return false; }
}
// ❌ Blocking install (hangs TUI for minutes)
execSync("cargo install my-tool");
// ✅ Async spawn for install
const child = spawn("cargo", ["install", "my-tool"], { stdio: "pipe" });
// ❌ Spawns a shell on every call
function hasOllama(): boolean {
try { execSync("which ollama", { stdio: "ignore" }); return true; }
catch { return false; }
}
// ✅ Cached
let _hasOllama: boolean | null = null;
function hasOllama(): boolean {
if (_hasOllama !== null) return _hasOllama;
try { execSync("which ollama", { stdio: "ignore" }); _hasOllama = true; }
catch { _hasOllama = false; }
return _hasOllama;
}
node:testOmegon uses the built-in Node.js test runner. Run with: npx tsx --test extensions/**/*.test.ts
import { describe, it } from "node:test";
import * as assert from "node:assert/strict";
describe("myModule", () => {
it("does the thing", () => {
assert.equal(myFunc(1), 2);
});
it("handles edge cases", () => {
assert.throws(() => myFunc(-1), /must be positive/);
});
});
*.test.ts co-located with source..js extensions in imports — TypeScript requires this for ESM resolution even though source files are .ts.default function for extension entry points.index.ts that re-exports everything) — import directly from the source module.// ❌ Bare specifier
import { checkAll } from "./deps";
// ✅ With .js extension
import { checkAll } from "./deps.js";
types.ts file.auth.ts, spec.ts) separate from extension wiring (index.ts).Projects using runtime transpilation (jiti, tsx, esbuild, etc.) must run tsc --noEmit as a separate type-checking gate. Runtime transpilers strip types without checking them — type errors compile and run but silently produce incorrect behavior.
# Add to package.json scripts
"typecheck": "tsc --noEmit"
"check": "tsc --noEmit && npm test"
Never redefine types that exist in an upstream SDK. When you copy-paste an interface instead of importing it, your local "shadow" drifts from the real type as the SDK evolves. The compiler can't catch the mismatch because it doesn't know they're supposed to be the same type.
// ❌ Shadow interface — drifts silently
interface ToolResult {
content: { type: string; text: string }[];
}
// ✅ Import from SDK
import type { AgentToolResult } from "@styrene-lab/pi-coding-agent";
Directive: Always import SDK types. Never redefine them locally. If an SDK type is not exported, file an issue or use module augmentation — don't copy the shape.