@hozu/cli 0.1.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 (76) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +15 -0
  3. package/bin/hozu.js +4 -0
  4. package/dist/commands/build.d.ts +4 -0
  5. package/dist/commands/build.d.ts.map +1 -0
  6. package/dist/commands/build.js +81 -0
  7. package/dist/commands/build.js.map +1 -0
  8. package/dist/commands/explain.d.ts +5 -0
  9. package/dist/commands/explain.d.ts.map +1 -0
  10. package/dist/commands/explain.js +135 -0
  11. package/dist/commands/explain.js.map +1 -0
  12. package/dist/commands/graph.d.ts +7 -0
  13. package/dist/commands/graph.d.ts.map +1 -0
  14. package/dist/commands/graph.js +137 -0
  15. package/dist/commands/graph.js.map +1 -0
  16. package/dist/commands/impact.d.ts +5 -0
  17. package/dist/commands/impact.d.ts.map +1 -0
  18. package/dist/commands/impact.js +27 -0
  19. package/dist/commands/impact.js.map +1 -0
  20. package/dist/commands/inspect.d.ts +4 -0
  21. package/dist/commands/inspect.d.ts.map +1 -0
  22. package/dist/commands/inspect.js +31 -0
  23. package/dist/commands/inspect.js.map +1 -0
  24. package/dist/commands/plan.d.ts +5 -0
  25. package/dist/commands/plan.d.ts.map +1 -0
  26. package/dist/commands/plan.js +30 -0
  27. package/dist/commands/plan.js.map +1 -0
  28. package/dist/commands/skill.d.ts +3 -0
  29. package/dist/commands/skill.d.ts.map +1 -0
  30. package/dist/commands/skill.js +27 -0
  31. package/dist/commands/skill.js.map +1 -0
  32. package/dist/commands/validate.d.ts +4 -0
  33. package/dist/commands/validate.d.ts.map +1 -0
  34. package/dist/commands/validate.js +96 -0
  35. package/dist/commands/validate.js.map +1 -0
  36. package/dist/contract.d.ts +107 -0
  37. package/dist/contract.d.ts.map +1 -0
  38. package/dist/contract.js +2 -0
  39. package/dist/contract.js.map +1 -0
  40. package/dist/errors.d.ts +8 -0
  41. package/dist/errors.d.ts.map +1 -0
  42. package/dist/errors.js +13 -0
  43. package/dist/errors.js.map +1 -0
  44. package/dist/index.d.ts +4 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +3 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/load.d.ts +9 -0
  49. package/dist/load.d.ts.map +1 -0
  50. package/dist/load.js +52 -0
  51. package/dist/load.js.map +1 -0
  52. package/dist/main.d.ts +2 -0
  53. package/dist/main.d.ts.map +1 -0
  54. package/dist/main.js +120 -0
  55. package/dist/main.js.map +1 -0
  56. package/dist/output.d.ts +5 -0
  57. package/dist/output.d.ts.map +1 -0
  58. package/dist/output.js +28 -0
  59. package/dist/output.js.map +1 -0
  60. package/dist/render.d.ts +5 -0
  61. package/dist/render.d.ts.map +1 -0
  62. package/dist/render.js +47 -0
  63. package/dist/render.js.map +1 -0
  64. package/dist/styles.d.ts +3 -0
  65. package/dist/styles.d.ts.map +1 -0
  66. package/dist/styles.js +41 -0
  67. package/dist/styles.js.map +1 -0
  68. package/package.json +54 -0
  69. package/schema/build.schema.json +29 -0
  70. package/schema/explain.schema.json +158 -0
  71. package/schema/graph.schema.json +109 -0
  72. package/schema/impact.schema.json +115 -0
  73. package/schema/inspect.schema.json +1658 -0
  74. package/schema/plan.schema.json +177 -0
  75. package/schema/skill.schema.json +21 -0
  76. package/schema/validate.schema.json +337 -0
@@ -0,0 +1,27 @@
1
+ import { stat } from 'node:fs/promises';
2
+ import { basename, join } from 'node:path';
3
+ import { AGENTS, runnerOf, writeAgentFiles } from 'create-hozu';
4
+ import { HozuCliError } from '../errors.js';
5
+ const exists = (path) => stat(path).then(() => true, () => false);
6
+ export async function runSkill(cwd, requested) {
7
+ let agent = requested;
8
+ if (agent && !AGENTS.includes(agent))
9
+ throw new HozuCliError('usage', `--agent must be one of ${AGENTS.join(', ')}`, [...AGENTS]);
10
+ if (!agent) {
11
+ const claude = await exists(join(cwd, '.claude/skills/hozu'));
12
+ const agents = await exists(join(cwd, '.agents/skills/hozu'));
13
+ agent = claude && agents ? 'both' : claude ? 'claude' : agents ? 'agents' : undefined;
14
+ }
15
+ if (!agent)
16
+ throw new HozuCliError('usage', 'No Hozu skill in this directory yet; choose where to write it', [
17
+ 'hozu skill --agent claude (CLAUDE.md + .claude/skills/hozu)',
18
+ 'hozu skill --agent agents (AGENTS.md + .agents/skills/hozu)',
19
+ 'hozu skill --agent both',
20
+ ]);
21
+ const written = await writeAgentFiles(cwd, agent, {
22
+ name: basename(cwd),
23
+ runner: runnerOf(process.env.npm_config_user_agent),
24
+ });
25
+ return { written };
26
+ }
27
+ //# sourceMappingURL=skill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill.js","sourceRoot":"","sources":["../../src/commands/skill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,EAAE,MAAM,EAAc,QAAQ,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE3E,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAE3C,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,EAAE,CAC9B,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CACb,GAAG,EAAE,CAAC,IAAI,EACV,GAAG,EAAE,CAAC,KAAK,CACZ,CAAA;AAEH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAW,EAAE,SAA6B;IACvE,IAAI,KAAK,GAAG,SAA8B,CAAA;IAC1C,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAClC,MAAM,IAAI,YAAY,CAAC,OAAO,EAAE,0BAA0B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAA;IAC7F,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC,CAAA;QAC7D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC,CAAA;QAC7D,KAAK,GAAG,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAA;IACvF,CAAC;IACD,IAAI,CAAC,KAAK;QACR,MAAM,IAAI,YAAY,CAAC,OAAO,EAAE,+DAA+D,EAAE;YAC/F,+DAA+D;YAC/D,+DAA+D;YAC/D,yBAAyB;SAC1B,CAAC,CAAA;IACJ,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,KAAK,EAAE;QAChD,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC;QACnB,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;KACpD,CAAC,CAAA;IACF,OAAO,EAAE,OAAO,EAAE,CAAA;AACpB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { ValidateOutput } from '../contract.ts';
2
+ import type { Loaded } from '../load.ts';
3
+ export declare function runValidate(loaded: Loaded, feature: string | undefined, cwd: string, updateLock?: boolean): Promise<ValidateOutput>;
4
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAY,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAE9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAmCxC,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,GAAG,EAAE,MAAM,EACX,UAAU,UAAQ,GACjB,OAAO,CAAC,cAAc,CAAC,CA2DzB"}
@@ -0,0 +1,96 @@
1
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { dirname, join as joinPath } from 'node:path';
3
+ import { codes, hashJson, join, resolveSource } from '@hozu/core/ir';
4
+ import { verify } from '@hozu/validator';
5
+ import { HozuCliError } from '../errors.js';
6
+ import { json, relativize } from '../output.js';
7
+ import { unknownClasses } from '../styles.js';
8
+ function firstDifference(a, b, pointer = '') {
9
+ if (a === b)
10
+ return null;
11
+ if (typeof a !== 'object' ||
12
+ typeof b !== 'object' ||
13
+ a === null ||
14
+ b === null ||
15
+ Array.isArray(a) !== Array.isArray(b))
16
+ return pointer;
17
+ const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
18
+ for (const key of [...keys].sort()) {
19
+ const diff = firstDifference(a[key] ?? null, b[key] ?? null, join(pointer, key));
20
+ if (diff !== null)
21
+ return diff;
22
+ }
23
+ return null;
24
+ }
25
+ function readLock(path) {
26
+ if (!existsSync(path))
27
+ return null;
28
+ try {
29
+ return JSON.parse(readFileSync(path, 'utf8'));
30
+ }
31
+ catch (error) {
32
+ throw new HozuCliError('config', `Cannot read ${path}: ${error.message}`);
33
+ }
34
+ }
35
+ export async function runValidate(loaded, feature, cwd, updateLock = false) {
36
+ const first = loaded.build(false);
37
+ const second = loaded.build(false);
38
+ const hash = hashJson(first.ir);
39
+ const lockPath = joinPath(dirname(loaded.path), 'hozu.lock.json');
40
+ const previous = readLock(lockPath);
41
+ const unknown = await unknownClasses(loaded.path, first);
42
+ const verified = verify(first.ir, { bindings: first.bindings, lock: previous, unknownClasses: unknown });
43
+ let diagnostics = [...first.diagnostics, ...verified.diagnostics];
44
+ if (hash !== hashJson(second.ir)) {
45
+ const pointer = firstDifference(first.ir, second.ir) ?? '';
46
+ const featureId = pointer.startsWith('/features/') ? (pointer.split('/')[2] ?? null) : null;
47
+ diagnostics.push({
48
+ code: 'HZ011',
49
+ severity: codes.HZ011.severity,
50
+ message: 'Building the project twice produced different IR',
51
+ location: { feature: featureId, pointer, source: null },
52
+ cause: 'A builder callback depends on something that changes between runs (time, randomness, mutable state).',
53
+ fix: {
54
+ summary: 'Make the callback a pure function of its reference arguments',
55
+ snippet: null,
56
+ patch: null,
57
+ },
58
+ });
59
+ }
60
+ if (diagnostics.length) {
61
+ const traced = loaded.build(true);
62
+ diagnostics = diagnostics.map((d) => ({
63
+ ...d,
64
+ location: { ...d.location, source: resolveSource(traced.sources, d.location.pointer) },
65
+ }));
66
+ }
67
+ const clean = !diagnostics.some((d) => d.severity === 'error');
68
+ let lock = previous ? 'checked' : 'missing';
69
+ if (updateLock) {
70
+ lock = clean && verified.lock ? 'updated' : 'skipped';
71
+ if (lock === 'updated')
72
+ writeFileSync(lockPath, json(verified.lock));
73
+ }
74
+ const coverage = {};
75
+ for (const [fid, entries] of Object.entries(verified.lock?.features ?? {})) {
76
+ if (feature && fid !== feature)
77
+ continue;
78
+ const list = Object.values(entries);
79
+ coverage[fid] = {
80
+ covered: list.filter((e) => Object.keys(e.contracts).length > 0).length,
81
+ total: list.length,
82
+ };
83
+ }
84
+ const selected = feature ? diagnostics.filter((d) => d.location.feature === feature) : diagnostics;
85
+ const errors = selected.filter((d) => d.severity === 'error').length;
86
+ return {
87
+ ok: errors === 0,
88
+ hash,
89
+ summary: { errors, warnings: selected.length - errors },
90
+ coverage,
91
+ lock,
92
+ styles: unknown ? 'checked' : 'unavailable',
93
+ diagnostics: relativize(selected, cwd),
94
+ };
95
+ }
96
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ import type { RoutePlan } from '@hozu/compiler';
2
+ import type { Diagnostic, ExportsIR, FeatureIR } from '@hozu/core/ir';
3
+ import type { Impact } from '@hozu/validator';
4
+ export interface CliError {
5
+ error: {
6
+ code: 'usage' | 'config' | 'unknown-feature' | 'build';
7
+ message: string;
8
+ suggestions: string[];
9
+ };
10
+ }
11
+ export interface Coverage {
12
+ covered: number;
13
+ total: number;
14
+ }
15
+ export interface ValidateOutput {
16
+ ok: boolean;
17
+ hash: string;
18
+ summary: {
19
+ errors: number;
20
+ warnings: number;
21
+ };
22
+ coverage: Record<string, Coverage>;
23
+ lock: 'missing' | 'checked' | 'updated' | 'skipped';
24
+ styles: 'checked' | 'unavailable';
25
+ diagnostics: Diagnostic[];
26
+ }
27
+ export interface InspectSummary {
28
+ states: number;
29
+ transitions: number;
30
+ events: number;
31
+ queries: number;
32
+ mutations: number;
33
+ views: number;
34
+ contracts: number;
35
+ hydrates: boolean;
36
+ imports: string[];
37
+ exports: ExportsIR;
38
+ }
39
+ export interface InspectOutput {
40
+ feature: string;
41
+ hash: string;
42
+ summary: InspectSummary;
43
+ ir: FeatureIR;
44
+ }
45
+ export type GraphNodeKind = 'state' | 'effect' | 'event' | 'feature' | 'view' | 'query';
46
+ export type GraphEdgeKind = 'on' | 'done' | 'failed' | 'after' | 'invoke' | 'import' | 'send' | 'reads' | 'embeds';
47
+ export interface GraphNode {
48
+ id: string;
49
+ kind: GraphNodeKind;
50
+ label: string;
51
+ initial: boolean;
52
+ final: boolean;
53
+ }
54
+ export interface GraphEdge {
55
+ from: string;
56
+ to: string;
57
+ kind: GraphEdgeKind;
58
+ label: string;
59
+ }
60
+ export interface GraphOutput {
61
+ feature: string;
62
+ nodes: GraphNode[];
63
+ edges: GraphEdge[];
64
+ }
65
+ export interface ExplainTransition {
66
+ id: string;
67
+ from: string;
68
+ to: string;
69
+ trigger: string;
70
+ guard: string | null;
71
+ assign: string[];
72
+ navigate: string | null;
73
+ coveredBy: string[];
74
+ }
75
+ export interface ExplainSend {
76
+ view: string;
77
+ node: string;
78
+ event: string;
79
+ handled: boolean;
80
+ }
81
+ export interface ExplainOutput {
82
+ feature: string;
83
+ state: string;
84
+ initial: boolean;
85
+ final: boolean;
86
+ invoke: {
87
+ effect: string;
88
+ input: string;
89
+ errors: string[];
90
+ } | null;
91
+ outgoing: ExplainTransition[];
92
+ incoming: ExplainTransition[];
93
+ sends: ExplainSend[];
94
+ }
95
+ export type ImpactOutput = Impact;
96
+ export interface PlanOutput extends RoutePlan {
97
+ soft: Record<string, string[]>;
98
+ }
99
+ export interface BuildOutput {
100
+ out: string;
101
+ manifest: string;
102
+ files: string[];
103
+ }
104
+ export interface SkillOutput {
105
+ written: string[];
106
+ }
107
+ //# sourceMappingURL=contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":""}
@@ -0,0 +1,8 @@
1
+ import type { CliError } from './contract.ts';
2
+ export declare class HozuCliError extends Error {
3
+ readonly code: CliError['error']['code'];
4
+ readonly suggestions: string[];
5
+ constructor(code: CliError['error']['code'], message: string, suggestions?: string[]);
6
+ toJSON(): CliError;
7
+ }
8
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAE7C,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAA;IACxC,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,CAAA;IAE9B,YAAY,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,GAAE,MAAM,EAAO,EAIvF;IAED,MAAM,IAAI,QAAQ,CAEjB;CACF"}
package/dist/errors.js ADDED
@@ -0,0 +1,13 @@
1
+ export class HozuCliError extends Error {
2
+ code;
3
+ suggestions;
4
+ constructor(code, message, suggestions = []) {
5
+ super(message);
6
+ this.code = code;
7
+ this.suggestions = suggestions;
8
+ }
9
+ toJSON() {
10
+ return { error: { code: this.code, message: this.message, suggestions: this.suggestions } };
11
+ }
12
+ }
13
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,YAAa,SAAQ,KAAK;IAC5B,IAAI,CAA2B;IAC/B,WAAW,CAAU;IAE9B,YAAY,IAA+B,EAAE,OAAe,EAAE,WAAW,GAAa,EAAE;QACtF,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAA;IAChC,CAAC;IAED,MAAM;QACJ,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,CAAA;IAC7F,CAAC;CACF"}
@@ -0,0 +1,4 @@
1
+ export { graphOf, mermaid } from './commands/graph.ts';
2
+ export type * from './contract.ts';
3
+ export { main } from './main.ts';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AACtD,mBAAmB,eAAe,CAAA;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { graphOf, mermaid } from './commands/graph.js';
2
+ export { main } from './main.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAEtD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA"}
package/dist/load.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { type BuildResult, type ProjectIR } from '@hozu/core/ir';
2
+ export interface Loaded {
3
+ path: string;
4
+ project: unknown;
5
+ build: (sources?: boolean) => BuildResult;
6
+ }
7
+ export declare function load(config: string | undefined, cwd: string): Promise<Loaded>;
8
+ export declare function requireFeature(ir: ProjectIR, id: string | undefined): import("@hozu/core/ir").FeatureIR;
9
+ //# sourceMappingURL=load.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../src/load.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,WAAW,EAAgB,KAAK,SAAS,EAAE,MAAM,eAAe,CAAA;AAI9E,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,WAAW,CAAA;CAC1C;AAED,wBAAsB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BnF;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,GAAG,SAAS,qCAOnE"}
package/dist/load.js ADDED
@@ -0,0 +1,52 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import { existsSync } from 'node:fs';
10
+ import { resolve } from 'node:path';
11
+ import { pathToFileURL } from 'node:url';
12
+ import { buildProject } from '@hozu/core/ir';
13
+ import { closest } from '@hozu/validator';
14
+ import { HozuCliError } from './errors.js';
15
+ export async function load(config, cwd) {
16
+ const path = resolve(cwd, config ?? 'hozu.config.ts');
17
+ if (!existsSync(path))
18
+ throw new HozuCliError('config', `No config found at ${path}`, [
19
+ 'Create hozu.config.ts exporting project({ ... }) as default, or pass --config <path>',
20
+ ]);
21
+ let mod;
22
+ try {
23
+ mod = await import(__rewriteRelativeImportExtension(pathToFileURL(path).href));
24
+ }
25
+ catch (error) {
26
+ throw new HozuCliError('config', `Failed to load ${path}: ${error instanceof Error ? error.message : String(error)}`);
27
+ }
28
+ const project = mod.default;
29
+ return {
30
+ path,
31
+ project,
32
+ build: (sources = false) => {
33
+ try {
34
+ return buildProject(project, { sources });
35
+ }
36
+ catch (error) {
37
+ throw new HozuCliError('config', error instanceof Error ? error.message : String(error));
38
+ }
39
+ },
40
+ };
41
+ }
42
+ export function requireFeature(ir, id) {
43
+ const ids = Object.keys(ir.features);
44
+ if (!id)
45
+ throw new HozuCliError('usage', 'Missing <feature> argument', ids);
46
+ const feature = ir.features[id];
47
+ if (feature)
48
+ return feature;
49
+ const guess = closest(id, ids);
50
+ throw new HozuCliError('unknown-feature', `Unknown feature "${id}"`, guess ? [guess] : ids);
51
+ }
52
+ //# sourceMappingURL=load.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.js","sourceRoot":"","sources":["../src/load.ts"],"names":[],"mappings":";;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAoB,YAAY,EAAkB,MAAM,eAAe,CAAA;AAC9E,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAQ1C,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,MAA0B,EAAE,GAAW;IAChE,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,MAAM,IAAI,gBAAgB,CAAC,CAAA;IACrD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QACnB,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,sBAAsB,IAAI,EAAE,EAAE;YAC7D,sFAAsF;SACvF,CAAC,CAAA;IACJ,IAAI,GAA0B,CAAA;IAC9B,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,MAAM,kCAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,EAAC,CAAA;IAC9C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,YAAY,CACpB,QAAQ,EACR,kBAAkB,IAAI,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACpF,CAAA;IACH,CAAC;IACD,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAA;IAC3B,OAAO;QACL,IAAI;QACJ,OAAO;QACP,KAAK,EAAE,CAAC,OAAO,GAAG,KAAK,EAAE,EAAE;YACzB,IAAI,CAAC;gBACH,OAAO,YAAY,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,CAAA;YAC3C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;YAC1F,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,EAAa,EAAE,EAAsB;IAClE,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAA;IACpC,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,YAAY,CAAC,OAAO,EAAE,4BAA4B,EAAE,GAAG,CAAC,CAAA;IAC3E,MAAM,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;IAC/B,IAAI,OAAO;QAAE,OAAO,OAAO,CAAA;IAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,EAAE,EAAE,GAAG,CAAC,CAAA;IAC9B,MAAM,IAAI,YAAY,CAAC,iBAAiB,EAAE,oBAAoB,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;AAC7F,CAAC"}
package/dist/main.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function main(argv: string[], cwd?: string, out?: (s: string) => void): Promise<number>;
2
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAkCA,wBAAsB,IAAI,CACxB,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,SAAgB,EACnB,GAAG,GAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAqC,GACxD,OAAO,CAAC,MAAM,CAAC,CAwFjB"}
package/dist/main.js ADDED
@@ -0,0 +1,120 @@
1
+ import { parseArgs } from 'node:util';
2
+ import { runBuild } from './commands/build.js';
3
+ import { describeExplain, runExplain } from './commands/explain.js';
4
+ import { mermaid, runGraph } from './commands/graph.js';
5
+ import { describeImpact, runImpact } from './commands/impact.js';
6
+ import { runInspect } from './commands/inspect.js';
7
+ import { describePlan, runPlan } from './commands/plan.js';
8
+ import { runSkill } from './commands/skill.js';
9
+ import { runValidate } from './commands/validate.js';
10
+ import { HozuCliError } from './errors.js';
11
+ import { load } from './load.js';
12
+ import { human, json } from './output.js';
13
+ const usage = `Usage: hozu <command> [options]
14
+
15
+ Commands:
16
+ validate [feature] Build the IR, run contracts, report diagnostics (exit 1 on errors)
17
+ inspect <feature> Print a feature's canonical IR and summary
18
+ graph <feature> Print a feature's state/effect/view graph (Mermaid, or --json)
19
+ explain <feature>.<state> Explain a state: transitions, guards, effects, covering contracts
20
+ impact <feature>.<symbol> What a query, mutation, tag, event, fn or view affects
21
+ plan <route> Derived render plan: regions, cache modes, hydration islands
22
+ build Write dist/public, dist/server/render.js and dist/manifest.json for deployment
23
+ skill Rewrite the agent skill for this Hozu version (--agent claude|agents|both)
24
+
25
+ Options:
26
+ --json Machine-readable output (schemas in @hozu/cli/schema)
27
+ --config <path> Config file (default: hozu.config.ts)
28
+ --update-lock validate: rewrite hozu.lock.json when there are no errors
29
+ --out <dir> build: output directory (default: dist)
30
+ --agent <agent> skill: claude, agents or both (default: the folders that exist)
31
+ -h, --help Show this help
32
+ `;
33
+ export async function main(argv, cwd = process.cwd(), out = (s) => process.stdout.write(s)) {
34
+ let asJson = false;
35
+ try {
36
+ const { values, positionals } = parseArgs({
37
+ args: argv,
38
+ allowPositionals: true,
39
+ strict: true,
40
+ options: {
41
+ json: { type: 'boolean', default: false },
42
+ config: { type: 'string' },
43
+ 'update-lock': { type: 'boolean', default: false },
44
+ out: { type: 'string' },
45
+ agent: { type: 'string' },
46
+ help: { type: 'boolean', short: 'h' },
47
+ },
48
+ });
49
+ asJson = values.json === true;
50
+ const [command, target] = positionals;
51
+ if (values.help || !command) {
52
+ out(usage);
53
+ return command || values.help ? 0 : 2;
54
+ }
55
+ const commands = ['validate', 'inspect', 'graph', 'explain', 'impact', 'plan', 'build', 'skill'];
56
+ if (!commands.includes(command))
57
+ throw new HozuCliError('usage', `Unknown command "${command}"`, commands);
58
+ if (command === 'skill') {
59
+ const result = await runSkill(cwd, values.agent);
60
+ out(asJson ? json(result) : `✔ wrote ${result.written.join(', ')}\n`);
61
+ return 0;
62
+ }
63
+ const loaded = await load(values.config, cwd);
64
+ if (command === 'validate') {
65
+ const result = await runValidate(loaded, target, cwd, values['update-lock'] === true);
66
+ if (asJson)
67
+ out(json(result));
68
+ else {
69
+ for (const d of result.diagnostics)
70
+ out(`${human(d)}\n\n`);
71
+ const coverage = Object.entries(result.coverage)
72
+ .map(([f, c]) => `${f} ${c.covered}/${c.total}`)
73
+ .join(', ');
74
+ out(`${result.ok ? '✔' : '✖'} ${result.summary.errors} errors, ${result.summary.warnings} warnings · contracts cover ${coverage || 'n/a'} · styles ${result.styles} · lock ${result.lock} (ir ${result.hash.slice(0, 12)})\n`);
75
+ }
76
+ return result.ok ? 0 : 1;
77
+ }
78
+ if (command === 'inspect') {
79
+ const result = runInspect(loaded, target);
80
+ out(asJson
81
+ ? json(result)
82
+ : `${json({ feature: result.feature, hash: result.hash, summary: result.summary })}`);
83
+ return 0;
84
+ }
85
+ if (command === 'build') {
86
+ const result = await runBuild(loaded, values.out, cwd);
87
+ out(asJson ? json(result) : `✔ wrote ${result.files.length} static files and ${result.manifest}\n`);
88
+ return 0;
89
+ }
90
+ if (command === 'plan') {
91
+ const result = runPlan(loaded, target);
92
+ out(asJson ? json(result) : describePlan(result));
93
+ return 0;
94
+ }
95
+ if (command === 'impact') {
96
+ const result = runImpact(loaded, target);
97
+ out(asJson ? json(result) : describeImpact(result));
98
+ return 0;
99
+ }
100
+ if (command === 'explain') {
101
+ const result = runExplain(loaded, target);
102
+ out(asJson ? json(result) : describeExplain(result));
103
+ return 0;
104
+ }
105
+ const graph = runGraph(loaded, target);
106
+ out(asJson ? json(graph) : mermaid(graph));
107
+ return 0;
108
+ }
109
+ catch (error) {
110
+ const e = error instanceof HozuCliError
111
+ ? error
112
+ : new HozuCliError('usage', error instanceof Error ? error.message : String(error));
113
+ if (asJson)
114
+ out(json(e.toJSON()));
115
+ else
116
+ process.stderr.write(`hozu: ${e.message}${e.suggestions.length ? `\n ${e.suggestions.join('\n ')}` : ''}\n`);
117
+ return 2;
118
+ }
119
+ }
120
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { type Diagnostic } from '@hozu/core/ir';
2
+ export declare const json: (value: unknown) => string;
3
+ export declare const relativize: (diagnostics: Diagnostic[], cwd: string) => Diagnostic[];
4
+ export declare function human(d: Diagnostic): string;
5
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AACA,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,eAAe,CAAA;AAEnE,eAAO,MAAM,IAAI,UAAW,OAAO,KAAG,MACiC,CAAA;AAEvE,eAAO,MAAM,UAAU,gBAAiB,UAAU,EAAE,OAAO,MAAM,KAAG,UAAU,EAW3E,CAAA;AAEH,wBAAgB,KAAK,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM,CAY3C"}
package/dist/output.js ADDED
@@ -0,0 +1,28 @@
1
+ import { relative } from 'node:path';
2
+ import { canonicalStringify } from '@hozu/core/ir';
3
+ export const json = (value) => `${JSON.stringify(JSON.parse(canonicalStringify(value)), null, 2)}\n`;
4
+ export const relativize = (diagnostics, cwd) => diagnostics.map((d) => d.location.source
5
+ ? {
6
+ ...d,
7
+ location: {
8
+ ...d.location,
9
+ source: { ...d.location.source, file: relative(cwd, d.location.source.file) },
10
+ },
11
+ }
12
+ : d);
13
+ export function human(d) {
14
+ const where = d.location.source
15
+ ? `${d.location.source.file}:${d.location.source.line}:${d.location.source.column}`
16
+ : `${d.location.pointer}`;
17
+ const lines = [
18
+ `${where} ${d.severity} ${d.code} ${d.message}`,
19
+ ` at ${d.location.pointer}`,
20
+ ` cause: ${d.cause}`,
21
+ ];
22
+ if (d.fix)
23
+ lines.push(` fix: ${d.fix.summary}${d.fix.patch ? ' (patch available with --json)' : ''}`);
24
+ if (d.fix?.snippet)
25
+ lines.push(d.fix.snippet.replace(/^/gm, ' '));
26
+ return lines.join('\n');
27
+ }
28
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,kBAAkB,EAAmB,MAAM,eAAe,CAAA;AAEnE,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,KAAc,EAAU,EAAE,CAC7C,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAA;AAEvE,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,WAAyB,EAAE,GAAW,EAAgB,EAAE,CACjF,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACpB,CAAC,CAAC,QAAQ,CAAC,MAAM;IACf,CAAC,CAAC;QACE,GAAG,CAAC;QACJ,QAAQ,EAAE;YACR,GAAG,CAAC,CAAC,QAAQ;YACb,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;SAC9E;KACF;IACH,CAAC,CAAC,CAAC,CACN,CAAA;AAEH,MAAM,UAAU,KAAK,CAAC,CAAa;IACjC,MAAM,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM;QAC7B,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE;QACnF,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAA;IAC3B,MAAM,KAAK,GAAG;QACZ,GAAG,KAAK,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE;QAClD,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE;QAC5B,YAAY,CAAC,CAAC,KAAK,EAAE;KACtB,CAAA;IACD,IAAI,CAAC,CAAC,GAAG;QAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACtG,IAAI,CAAC,CAAC,GAAG,EAAE,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAA;IACpE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { AssignOp, GuardExpr, ValueExpr } from '@hozu/core/ir';
2
+ export declare function renderValue(v: ValueExpr): string;
3
+ export declare function renderGuard(g: GuardExpr): string;
4
+ export declare function renderAssign(a: AssignOp): string;
5
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAKnE,wBAAgB,WAAW,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAWhD;AAID,wBAAgB,WAAW,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAYhD;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,CAYhD"}
package/dist/render.js ADDED
@@ -0,0 +1,47 @@
1
+ const local = (ref) => ref.slice(ref.indexOf('.') + 1);
2
+ const suffix = (path) => path.map((p) => `.${p}`).join('');
3
+ export function renderValue(v) {
4
+ if ('literal' in v)
5
+ return JSON.stringify(v.literal);
6
+ if ('object' in v)
7
+ return `{ ${Object.entries(v.object)
8
+ .map(([k, x]) => `${k}: ${renderValue(x)}`)
9
+ .join(', ')} }`;
10
+ if ('fn' in v)
11
+ return `${local(v.fn)}(${renderValue(v.arg)})`;
12
+ if ('test' in v)
13
+ return `(${renderGuard(v.test)})`;
14
+ if ('link' in v)
15
+ return `link(${local(v.link)}, ${renderValue(v.params)}, ${renderValue(v.search)})`;
16
+ if (v.ref === 'binding')
17
+ return `item${v.depth}${suffix(v.path)}`;
18
+ return `${v.ref}${suffix(v.path)}`;
19
+ }
20
+ const symbols = { eq: '==', neq: '!=', lt: '<', lte: '<=', gt: '>', gte: '>=' };
21
+ export function renderGuard(g) {
22
+ switch (g.op) {
23
+ case 'and':
24
+ case 'or':
25
+ return g.args.map((a) => `(${renderGuard(a)})`).join(g.op === 'and' ? ' && ' : ' || ');
26
+ case 'not':
27
+ return `!(${renderGuard(g.arg)})`;
28
+ case 'fn':
29
+ return `${local(g.fn)}(${renderValue(g.arg)})`;
30
+ default:
31
+ return `${renderValue(g.left)} ${symbols[g.op]} ${renderValue(g.right)}`;
32
+ }
33
+ }
34
+ export function renderAssign(a) {
35
+ const target = `context${suffix(a.path)}`;
36
+ switch (a.op) {
37
+ case 'set':
38
+ return `${target} = ${renderValue(a.value)}`;
39
+ case 'append':
40
+ return `${target}.push(${renderValue(a.value)})`;
41
+ case 'inc':
42
+ return `${target} += ${renderValue(a.value)}`;
43
+ case 'removeWhere':
44
+ return `${target} = ${target}.filter(x => x.${a.key} != ${renderValue(a.value)})`;
45
+ }
46
+ }
47
+ //# sourceMappingURL=render.js.map