@freetesh/canon 0.15.0 → 0.17.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.
Files changed (72) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +24 -7
  4. package/cli/dist/api.d.ts +2 -2
  5. package/cli/dist/api.js +2 -2
  6. package/cli/dist/checks/{external.js → commands.js} +2 -0
  7. package/cli/dist/checks/designs.d.ts +5 -0
  8. package/cli/dist/checks/designs.js +33 -0
  9. package/cli/dist/checks/index.js +6 -3
  10. package/cli/dist/checks/stale-copies.d.ts +2 -0
  11. package/cli/dist/checks/stale-copies.js +18 -0
  12. package/cli/dist/checks/{copies.d.ts → standards-copies.d.ts} +0 -1
  13. package/cli/dist/checks/{copies.js → standards-copies.js} +0 -16
  14. package/cli/dist/commands/add.d.ts +1 -1
  15. package/cli/dist/commands/add.js +1 -1
  16. package/cli/dist/commands/check.d.ts +1 -1
  17. package/cli/dist/commands/check.js +2 -2
  18. package/cli/dist/commands/copies.d.ts +1 -1
  19. package/cli/dist/commands/hooks.d.ts +1 -1
  20. package/cli/dist/commands/hooks.js +2 -2
  21. package/cli/dist/commands/init.d.ts +1 -1
  22. package/cli/dist/commands/init.js +2 -2
  23. package/cli/dist/commands/learn.d.ts +1 -1
  24. package/cli/dist/commands/learn.js +2 -2
  25. package/cli/dist/commands/pipeline.d.ts +1 -1
  26. package/cli/dist/{search → commands}/search.js +1 -1
  27. package/cli/dist/commands/standards.d.ts +1 -1
  28. package/cli/dist/commands/status.d.ts +1 -1
  29. package/cli/dist/commands/sync.d.ts +1 -1
  30. package/cli/dist/commands/sync.js +1 -1
  31. package/cli/dist/commands/ui.d.ts +1 -1
  32. package/cli/dist/commands/ui.js +2 -2
  33. package/cli/dist/config/load.js +18 -6
  34. package/cli/dist/config/schema.d.ts +24 -3
  35. package/cli/dist/config/schema.js +17 -3
  36. package/cli/dist/format.d.ts +1 -1
  37. package/cli/dist/index.js +2 -2
  38. package/cli/dist/init.js +2 -2
  39. package/cli/dist/packs.d.ts +3 -1
  40. package/cli/dist/standards.d.ts +11 -6
  41. package/cli/dist/standards.js +37 -17
  42. package/cli/dist/status.d.ts +1 -1
  43. package/cli/dist/status.js +1 -1
  44. package/package.json +3 -3
  45. package/packs/expo/pack.yaml +1 -1
  46. package/packs/firebase/pack.yaml +1 -1
  47. package/packs/react/pack.yaml +1 -1
  48. package/packs/revenuecat/pack.yaml +1 -1
  49. package/packs/uniwind/pack.yaml +1 -1
  50. package/scripts/check-designs.py +709 -0
  51. package/standards/README.md +23 -6
  52. package/standards/agent-contract.md +21 -6
  53. package/standards/context-layout.md +41 -6
  54. package/standards/library/design-sets.md +857 -0
  55. package/standards/library/expo.md +54 -0
  56. package/standards/library/frontend.md +44 -0
  57. package/standards/library/performance.md +45 -0
  58. package/standards/library/pipeline.md +42 -0
  59. package/standards/library/secrets.md +37 -0
  60. package/standards/library/store-listing.md +122 -0
  61. /package/cli/dist/{run.d.ts → check.d.ts} +0 -0
  62. /package/cli/dist/{run.js → check.js} +0 -0
  63. /package/cli/dist/checks/{external.d.ts → commands.d.ts} +0 -0
  64. /package/cli/dist/checks/{metrics.d.ts → metrics-definitions.d.ts} +0 -0
  65. /package/cli/dist/checks/{metrics.js → metrics-definitions.js} +0 -0
  66. /package/cli/dist/{search → commands}/mcp.d.ts +0 -0
  67. /package/cli/dist/{search → commands}/mcp.js +0 -0
  68. /package/cli/dist/{search → commands}/search.d.ts +0 -0
  69. /package/cli/dist/{commands → lib}/env.d.ts +0 -0
  70. /package/cli/dist/{commands → lib}/env.js +0 -0
  71. /package/cli/dist/{search → lib}/qmd.d.ts +0 -0
  72. /package/cli/dist/{search → lib}/qmd.js +0 -0
@@ -4,11 +4,16 @@ export interface Standard {
4
4
  /** "canon" for a built-in default, else the configured folder it came from. */
5
5
  from: string;
6
6
  }
7
- /** canon's default standards, then each configured folder in order; a later file of the same name replaces an earlier one. */
8
- export declare function resolveStandards(canonRoot: string, folders: string[]): Standard[];
7
+ /** The opt-in standards canon ships; a repo imports one by name under `standards:`. */
8
+ export declare function libraryStandards(canonRoot: string): string[];
9
9
  /**
10
- * Principle headings from canon's constitution and every configured one. A
11
- * constitution in a folder extends rather than replaces: it adds principles,
12
- * and restating an ID rewords it.
10
+ * canon's defaults, then each `standards:` entry in order: a name imports canon's library
11
+ * standard, a folder adds its files. A later file of the same name replaces an earlier one.
13
12
  */
14
- export declare function constitutionTitles(canonRoot: string, folders: string[]): string[];
13
+ export declare function resolveStandards(canonRoot: string, entries: string[]): Standard[];
14
+ /**
15
+ * Principle headings from canon's constitution, every imported library standard
16
+ * and every configured folder's constitution. They extend rather than replace:
17
+ * each adds principles, and restating an ID rewords it.
18
+ */
19
+ export declare function constitutionTitles(canonRoot: string, entries: string[]): string[];
@@ -1,35 +1,55 @@
1
1
  import { existsSync, readdirSync, readFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
+ import { isStandardName } from "./config/schema.js";
3
4
  const NOT_STANDARDS = new Set(["README.md"]);
4
5
  const PRINCIPLE = /^### (C-\d{2}) (.+)$/;
5
6
  function markdownIn(dir) {
6
7
  return readdirSync(dir).filter((file) => file.endsWith(".md") && !NOT_STANDARDS.has(file));
7
8
  }
8
- /** canon's default standards, then each configured folder in order; a later file of the same name replaces an earlier one. */
9
- export function resolveStandards(canonRoot, folders) {
9
+ /** The opt-in standards canon ships; a repo imports one by name under `standards:`. */
10
+ export function libraryStandards(canonRoot) {
11
+ const dir = join(canonRoot, "standards", "library");
12
+ return existsSync(dir) ? markdownIn(dir).map((file) => file.replace(/\.md$/, "")).sort() : [];
13
+ }
14
+ function libraryFile(canonRoot, name) {
15
+ const path = join(canonRoot, "standards", "library", `${name}.md`);
16
+ if (!existsSync(path))
17
+ throw new Error(`no canon standard named ${name} — canon has: ${libraryStandards(canonRoot).join(", ")}`);
18
+ return path;
19
+ }
20
+ /**
21
+ * canon's defaults, then each `standards:` entry in order: a name imports canon's library
22
+ * standard, a folder adds its files. A later file of the same name replaces an earlier one.
23
+ */
24
+ export function resolveStandards(canonRoot, entries) {
10
25
  const byName = new Map();
11
- const sources = [{ dir: join(canonRoot, "standards"), from: "canon" }, ...folders.map((dir) => ({ dir, from: dir }))];
12
- for (const { dir, from } of sources) {
13
- if (!existsSync(dir))
14
- throw new Error(`standards folder not found: ${dir}`);
15
- for (const file of markdownIn(dir)) {
16
- const name = file.replace(/\.md$/, "");
17
- // Constitutions add up (see constitutionTitles), so each one keeps its own entry.
18
- const key = name === "constitution" ? `${name}:${from}` : name;
19
- byName.set(key, { name, path: join(dir, file), from });
26
+ const add = (name, path, from) => {
27
+ // Constitutions add up (see constitutionTitles), so each one keeps its own entry.
28
+ byName.set(name === "constitution" ? `${name}:${from}` : name, { name, path, from });
29
+ };
30
+ const defaults = join(canonRoot, "standards");
31
+ for (const entry of [defaults, ...entries]) {
32
+ if (isStandardName(entry)) {
33
+ add(entry, libraryFile(canonRoot, entry), "canon library");
34
+ continue;
20
35
  }
36
+ if (!existsSync(entry))
37
+ throw new Error(`standards folder not found: ${entry}`);
38
+ const from = entry === defaults ? "canon" : entry;
39
+ for (const file of markdownIn(entry))
40
+ add(file.replace(/\.md$/, ""), join(entry, file), from);
21
41
  }
22
42
  return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name) || Number(a.from !== "canon") - Number(b.from !== "canon"));
23
43
  }
24
44
  /**
25
- * Principle headings from canon's constitution and every configured one. A
26
- * constitution in a folder extends rather than replaces: it adds principles,
27
- * and restating an ID rewords it.
45
+ * Principle headings from canon's constitution, every imported library standard
46
+ * and every configured folder's constitution. They extend rather than replace:
47
+ * each adds principles, and restating an ID rewords it.
28
48
  */
29
- export function constitutionTitles(canonRoot, folders) {
49
+ export function constitutionTitles(canonRoot, entries) {
30
50
  const titles = new Map();
31
- for (const dir of [join(canonRoot, "standards"), ...folders]) {
32
- const file = join(dir, "constitution.md");
51
+ const files = [join(canonRoot, "standards"), ...entries].map((entry) => isStandardName(entry) ? libraryFile(canonRoot, entry) : join(entry, "constitution.md"));
52
+ for (const file of files) {
33
53
  if (!existsSync(file))
34
54
  continue;
35
55
  for (const line of readFileSync(file, "utf8").split("\n")) {
@@ -1,3 +1,3 @@
1
- import { type RunOptions } from "./run.ts";
1
+ import { type RunOptions } from "./check.ts";
2
2
  export declare function canonVersion(canonRoot: string): string;
3
3
  export declare function buildStatus(repo: string, options: RunOptions): string;
@@ -1,7 +1,7 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { loadConfig } from "./config/load.js";
4
- import { runChecks } from "./run.js";
4
+ import { runChecks } from "./check.js";
5
5
  export function canonVersion(canonRoot) {
6
6
  const manifest = join(canonRoot, ".claude-plugin", "plugin.json");
7
7
  if (!existsSync(manifest))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@freetesh/canon",
3
- "version": "0.15.0",
3
+ "version": "0.17.0",
4
4
  "description": "canon CLI: keep your domain knowledge and AI rules in your repo, and enforce them.",
5
5
  "license": "MIT",
6
6
  "author": "Ritesh Firodiya",
@@ -22,6 +22,7 @@
22
22
  "packs",
23
23
  "templates",
24
24
  "scripts/log-verdict.mjs",
25
+ "scripts/check-designs.py",
25
26
  ".claude-plugin"
26
27
  ],
27
28
  "engines": {
@@ -35,8 +36,7 @@
35
36
  "test": "vitest run --root cli",
36
37
  "coverage": "vitest run --root cli --coverage",
37
38
  "typecheck": "tsc -p cli",
38
- "prepack": "pnpm build",
39
- "release": "bash scripts/publish.sh"
39
+ "prepack": "pnpm build"
40
40
  },
41
41
  "dependencies": {
42
42
  "@clack/prompts": "^1.8.1",
@@ -1,5 +1,5 @@
1
1
  name: expo
2
2
  description: Expo / React Native — versioned SDK docs
3
- kinds: [expo-app]
3
+ kinds: [mobile]
4
4
  docs:
5
5
  - https://docs.expo.dev/llms.txt
@@ -1,5 +1,5 @@
1
1
  name: firebase
2
2
  description: Firebase — auth, Firestore, rules, functions
3
- kinds: [expo-app, web]
3
+ kinds: [mobile, web]
4
4
  docs:
5
5
  - https://firebase.google.com/docs/llms.txt
@@ -1,5 +1,5 @@
1
1
  name: react
2
2
  description: React — components, hooks, rendering
3
- kinds: [expo-app, web]
3
+ kinds: [mobile, web]
4
4
  docs:
5
5
  - https://react.dev/llms.txt
@@ -1,5 +1,5 @@
1
1
  name: revenuecat
2
2
  description: RevenueCat — subscriptions, paywalls, entitlements
3
- kinds: [expo-app, web]
3
+ kinds: [mobile, web]
4
4
  docs:
5
5
  - https://www.revenuecat.com/docs/llms.txt
@@ -1,5 +1,5 @@
1
1
  name: uniwind
2
2
  description: UniWind — Tailwind classes for React Native
3
- kinds: [expo-app]
3
+ kinds: [mobile]
4
4
  docs:
5
5
  - https://docs.uniwind.dev/llms.txt