mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
2bb9f3fdf4
Introduce machinery for keeping examples/integrations/* demos aligned to a single north-star (langgraph-python). Built first so the upcoming langgraph-js and langgraph-fastapi alignment PRs have a mechanical baseline to work against instead of manual copy-paste. - examples/integrations/_parity/manifest.json declares verbatim files, tracked package.json keys, and expected agent surface (tool names, state keys) per instance plus allowed-divergence lists. - _parity/sync.ts copies verbatim files + rewrites tracked package.json keys from north-star to a target instance. Dry-run supported. - _parity/verify.ts diffs each instance vs north-star and exits non-zero on unexpected drift. Checks verbatim content, tracked keys, canonical prompt equality, and agent-surface grep-level presence. - Canonical prompt at _parity/canonical/PROMPT.md — synced into each instance's agent/PROMPT.md on parity:sync. - Root package.json: pnpm parity:sync, parity:verify, parity:check. - CI: .github/workflows/integrations_parity.yml runs parity:check on PRs touching examples/integrations/**. - Skill: .claude/skills/copilotkit-demo-parity/SKILL.md teaches agents how to drive sync/verify and handle manual-merge zones (agent code, api route, Dockerfile). Does NOT touch the existing instance demos yet. Those alignment commits follow in the same PR.
48 lines
1.2 KiB
TypeScript
48 lines
1.2 KiB
TypeScript
import { createHash } from "node:crypto";
|
|
import { readFileSync, statSync } from "node:fs";
|
|
|
|
export function sha256(buf: Buffer | string): string {
|
|
return createHash("sha256").update(buf).digest("hex");
|
|
}
|
|
|
|
export function fileSha256(path: string): string {
|
|
return sha256(readFileSync(path));
|
|
}
|
|
|
|
export function fileExists(path: string): boolean {
|
|
try {
|
|
statSync(path);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export function getByPath(obj: unknown, path: string): unknown {
|
|
const parts = path.split(".");
|
|
let cur: unknown = obj;
|
|
for (const part of parts) {
|
|
if (cur == null || typeof cur !== "object") return undefined;
|
|
cur = (cur as Record<string, unknown>)[part];
|
|
}
|
|
return cur;
|
|
}
|
|
|
|
export function setByPath(
|
|
obj: Record<string, unknown>,
|
|
path: string,
|
|
value: unknown,
|
|
): void {
|
|
const parts = path.split(".");
|
|
let cur: Record<string, unknown> = obj;
|
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
const key = parts[i]!;
|
|
const next = cur[key];
|
|
if (next == null || typeof next !== "object" || Array.isArray(next)) {
|
|
cur[key] = {};
|
|
}
|
|
cur = cur[key] as Record<string, unknown>;
|
|
}
|
|
cur[parts[parts.length - 1]!] = value;
|
|
}
|