@cogitato/kit-cli 0.0.0-stage → 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.
- package/LICENSE +202 -0
- package/README.md +34 -2
- package/bin/kit.js +4 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +204 -0
- package/dist/cli.js.map +1 -0
- package/dist/doctor.d.ts +19 -0
- package/dist/doctor.js +72 -0
- package/dist/doctor.js.map +1 -0
- package/dist/errors.d.ts +8 -0
- package/dist/errors.js +9 -0
- package/dist/errors.js.map +1 -0
- package/dist/export-flows.d.ts +8 -0
- package/dist/export-flows.js +15 -0
- package/dist/export-flows.js.map +1 -0
- package/dist/flows.d.ts +38 -0
- package/dist/flows.js +141 -0
- package/dist/flows.js.map +1 -0
- package/dist/format.d.ts +3 -0
- package/dist/format.js +27 -0
- package/dist/format.js.map +1 -0
- package/dist/gaps.d.ts +21 -0
- package/dist/gaps.js +52 -0
- package/dist/gaps.js.map +1 -0
- package/dist/hook.d.ts +33 -0
- package/dist/hook.js +78 -0
- package/dist/hook.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/issue.d.ts +17 -0
- package/dist/issue.js +65 -0
- package/dist/issue.js.map +1 -0
- package/dist/links.d.ts +16 -0
- package/dist/links.js +61 -0
- package/dist/links.js.map +1 -0
- package/dist/preview.d.ts +16 -0
- package/dist/preview.js +38 -0
- package/dist/preview.js.map +1 -0
- package/dist/project.d.ts +35 -0
- package/dist/project.js +88 -0
- package/dist/project.js.map +1 -0
- package/dist/registry.d.ts +67 -0
- package/dist/registry.js +224 -0
- package/dist/registry.js.map +1 -0
- package/dist/rules/css-values.d.ts +31 -0
- package/dist/rules/css-values.js +185 -0
- package/dist/rules/css-values.js.map +1 -0
- package/dist/rules/css.d.ts +4 -0
- package/dist/rules/css.js +39 -0
- package/dist/rules/css.js.map +1 -0
- package/dist/rules/tsx.d.ts +24 -0
- package/dist/rules/tsx.js +190 -0
- package/dist/rules/tsx.js.map +1 -0
- package/dist/save.d.ts +27 -0
- package/dist/save.js +125 -0
- package/dist/save.js.map +1 -0
- package/dist/scaffold.d.ts +42 -0
- package/dist/scaffold.js +230 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/snapshots.d.ts +23 -0
- package/dist/snapshots.js +126 -0
- package/dist/snapshots.js.map +1 -0
- package/dist/status.d.ts +14 -0
- package/dist/status.js +38 -0
- package/dist/status.js.map +1 -0
- package/dist/validate.d.ts +14 -0
- package/dist/validate.js +64 -0
- package/dist/validate.js.map +1 -0
- package/package.json +48 -3
package/dist/flows.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type FlowManifest } from "@cogitato/contract";
|
|
2
|
+
import type { Issue } from "./issue.js";
|
|
3
|
+
import { type Project } from "./project.js";
|
|
4
|
+
import type { Registry } from "./registry.js";
|
|
5
|
+
/**
|
|
6
|
+
* Builds flows.json content from the registry. Screens are ordered by their first appearance
|
|
7
|
+
* in a flow (so the canvas reads left to right), then by id.
|
|
8
|
+
*/
|
|
9
|
+
export declare function buildManifest(reg: Registry, commit?: string): {
|
|
10
|
+
manifest: FlowManifest;
|
|
11
|
+
issues: Issue[];
|
|
12
|
+
};
|
|
13
|
+
export declare function currentCommit(project: Project): string | undefined;
|
|
14
|
+
export declare const serializeManifest: (m: FlowManifest) => string;
|
|
15
|
+
/**
|
|
16
|
+
* Compares manifests ignoring `commit`, which changes on every commit, and review `status`, which
|
|
17
|
+
* is set on the canvas rather than derived from code. Pass `status: true` to compare it too.
|
|
18
|
+
*/
|
|
19
|
+
export declare function sameManifest(a: FlowManifest, b: FlowManifest, opts?: {
|
|
20
|
+
status?: boolean;
|
|
21
|
+
}): boolean;
|
|
22
|
+
/** Review statuses from the current flows.json, for the states that still exist. */
|
|
23
|
+
export declare function keptStatus(project: Project, manifest: FlowManifest): FlowManifest["status"] | undefined;
|
|
24
|
+
export declare function readFlowsJson(project: Project): FlowManifest | undefined;
|
|
25
|
+
/** Checks that design/flows.json matches the code. A warning: the next export fixes it. */
|
|
26
|
+
export declare function staleIssue(project: Project, manifest: FlowManifest): Issue | undefined;
|
|
27
|
+
export interface ExportResult {
|
|
28
|
+
manifest: FlowManifest;
|
|
29
|
+
issues: Issue[];
|
|
30
|
+
/** True when the file on disk differs from the export (ignoring commit). */
|
|
31
|
+
changed: boolean;
|
|
32
|
+
written: boolean;
|
|
33
|
+
}
|
|
34
|
+
/** Writes design/flows.json, unless there are problems or `check` is set. */
|
|
35
|
+
export declare function writeManifest(project: Project, built: {
|
|
36
|
+
manifest: FlowManifest;
|
|
37
|
+
issues: Issue[];
|
|
38
|
+
}, check: boolean): ExportResult;
|
package/dist/flows.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { SCHEMA_VERSIONS, validateFlows } from "@cogitato/contract";
|
|
4
|
+
import { LAYOUT } from "./project.js";
|
|
5
|
+
const FLOWS_SCHEMA = "../node_modules/@cogitato/contract/schema/flows.schema.json";
|
|
6
|
+
function unknownStep(reg, flow, ref, at) {
|
|
7
|
+
const dot = ref.lastIndexOf(".");
|
|
8
|
+
const screenId = ref.slice(0, dot);
|
|
9
|
+
const state = ref.slice(dot + 1);
|
|
10
|
+
const screen = reg.screens.find((s) => s.id === screenId);
|
|
11
|
+
const reason = dot < 0
|
|
12
|
+
? `steps are written as "{screen id}.{state}", like "checkout.payment.default"`
|
|
13
|
+
: screen
|
|
14
|
+
? `the ${screen.title} screen has no state called "${state}" (it has: ${screen.fixtures.map((f) => `"${f.key}"`).join(", ")})`
|
|
15
|
+
: `there's no screen with the id "${screenId}"`;
|
|
16
|
+
return {
|
|
17
|
+
code: "code-unknown-flow-step",
|
|
18
|
+
severity: "error",
|
|
19
|
+
file: at.file,
|
|
20
|
+
path: "",
|
|
21
|
+
line: at.line,
|
|
22
|
+
column: at.column,
|
|
23
|
+
message: `The "${flow.title}" flow mentions "${ref}", but ${reason}.`,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Builds flows.json content from the registry. Screens are ordered by their first appearance
|
|
28
|
+
* in a flow (so the canvas reads left to right), then by id.
|
|
29
|
+
*/
|
|
30
|
+
export function buildManifest(reg, commit) {
|
|
31
|
+
const issues = [];
|
|
32
|
+
const known = new Set(reg.screens.flatMap((s) => s.fixtures.map((f) => `${s.id}.${f.key}`)));
|
|
33
|
+
const flows = reg.flows.map((flow) => {
|
|
34
|
+
for (const e of flow.edges) {
|
|
35
|
+
if (!known.has(e.from))
|
|
36
|
+
issues.push(unknownStep(reg, flow, e.from, e));
|
|
37
|
+
if (!known.has(e.to))
|
|
38
|
+
issues.push(unknownStep(reg, flow, e.to, e));
|
|
39
|
+
}
|
|
40
|
+
for (const n of flow.nodes ?? [])
|
|
41
|
+
if (!known.has(n.ref))
|
|
42
|
+
issues.push(unknownStep(reg, flow, n.ref, n.at));
|
|
43
|
+
const nodes = flow.nodes ? flow.nodes.map((n) => n.ref) : [...new Set(flow.edges.flatMap((e) => [e.from, e.to]))];
|
|
44
|
+
return {
|
|
45
|
+
id: flow.id,
|
|
46
|
+
title: flow.title,
|
|
47
|
+
nodes,
|
|
48
|
+
edges: flow.edges.map(({ from, to, label }) => (label !== undefined ? { from, to, label } : { from, to })),
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
const order = new Map();
|
|
52
|
+
for (const f of flows)
|
|
53
|
+
for (const node of f.nodes) {
|
|
54
|
+
const screenId = node.slice(0, node.lastIndexOf("."));
|
|
55
|
+
if (!order.has(screenId))
|
|
56
|
+
order.set(screenId, order.size);
|
|
57
|
+
}
|
|
58
|
+
const rank = (id) => order.get(id) ?? Number.MAX_SAFE_INTEGER;
|
|
59
|
+
const screens = [...reg.screens]
|
|
60
|
+
.sort((a, b) => rank(a.id) - rank(b.id) || a.id.localeCompare(b.id))
|
|
61
|
+
.map((s) => ({
|
|
62
|
+
id: s.id,
|
|
63
|
+
route: s.route,
|
|
64
|
+
title: s.title,
|
|
65
|
+
states: s.fixtures.map((f) => ({ id: f.key, fixture: f.key, title: f.title })),
|
|
66
|
+
}));
|
|
67
|
+
const manifest = {
|
|
68
|
+
$schema: FLOWS_SCHEMA,
|
|
69
|
+
schemaVersion: SCHEMA_VERSIONS.flows,
|
|
70
|
+
...(commit ? { commit } : {}),
|
|
71
|
+
screens,
|
|
72
|
+
flows,
|
|
73
|
+
};
|
|
74
|
+
return { manifest, issues };
|
|
75
|
+
}
|
|
76
|
+
export function currentCommit(project) {
|
|
77
|
+
const r = spawnSync("git", ["rev-parse", "--short", "HEAD"], { cwd: project.root, encoding: "utf8" });
|
|
78
|
+
const sha = r.status === 0 ? r.stdout.trim() : "";
|
|
79
|
+
return /^[0-9a-f]{7,40}$/.test(sha) ? sha : undefined;
|
|
80
|
+
}
|
|
81
|
+
export const serializeManifest = (m) => JSON.stringify(m, null, 2) + "\n";
|
|
82
|
+
/**
|
|
83
|
+
* Compares manifests ignoring `commit`, which changes on every commit, and review `status`, which
|
|
84
|
+
* is set on the canvas rather than derived from code. Pass `status: true` to compare it too.
|
|
85
|
+
*/
|
|
86
|
+
export function sameManifest(a, b, opts = {}) {
|
|
87
|
+
const strip = ({ commit: _c, status, ...rest }) => JSON.stringify(opts.status ? { ...rest, status: status ?? {} } : rest);
|
|
88
|
+
return strip(a) === strip(b);
|
|
89
|
+
}
|
|
90
|
+
/** Review statuses from the current flows.json, for the states that still exist. */
|
|
91
|
+
export function keptStatus(project, manifest) {
|
|
92
|
+
const existing = readFlowsJson(project)?.status;
|
|
93
|
+
if (!existing)
|
|
94
|
+
return undefined;
|
|
95
|
+
const nodes = new Set(manifest.screens.flatMap((s) => s.states.map((st) => `${s.id}.${st.id}`)));
|
|
96
|
+
const kept = Object.fromEntries(Object.entries(existing).filter(([node]) => nodes.has(node)));
|
|
97
|
+
return Object.keys(kept).length ? kept : undefined;
|
|
98
|
+
}
|
|
99
|
+
export function readFlowsJson(project) {
|
|
100
|
+
const path = project.abs(LAYOUT.flowsJson);
|
|
101
|
+
if (!existsSync(path))
|
|
102
|
+
return undefined;
|
|
103
|
+
try {
|
|
104
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/** Checks that design/flows.json matches the code. A warning: the next export fixes it. */
|
|
111
|
+
export function staleIssue(project, manifest) {
|
|
112
|
+
const existing = readFlowsJson(project);
|
|
113
|
+
if (existing && sameManifest(existing, manifest))
|
|
114
|
+
return undefined;
|
|
115
|
+
return {
|
|
116
|
+
code: "code-flows-stale",
|
|
117
|
+
severity: "warning",
|
|
118
|
+
file: LAYOUT.flowsJson,
|
|
119
|
+
path: "",
|
|
120
|
+
message: existing
|
|
121
|
+
? "flows.json is out of date with the screens and flows in the code. Run the flow export to update it."
|
|
122
|
+
: "flows.json hasn't been created yet. Run the flow export to create it.",
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/** Writes design/flows.json, unless there are problems or `check` is set. */
|
|
126
|
+
export function writeManifest(project, built, check) {
|
|
127
|
+
const issues = [...built.issues];
|
|
128
|
+
if (!issues.some((i) => i.severity === "error")) {
|
|
129
|
+
// Safety net: the shared validator must accept what we're about to write.
|
|
130
|
+
const r = validateFlows(built.manifest, LAYOUT.flowsJson);
|
|
131
|
+
issues.push(...r.issues);
|
|
132
|
+
}
|
|
133
|
+
const existing = readFlowsJson(project);
|
|
134
|
+
const changed = !existing || !sameManifest(existing, built.manifest, { status: true });
|
|
135
|
+
const ok = !issues.some((i) => i.severity === "error");
|
|
136
|
+
const written = ok && !check && (changed || existing?.commit !== built.manifest.commit);
|
|
137
|
+
if (written)
|
|
138
|
+
writeFileSync(project.abs(LAYOUT.flowsJson), serializeManifest(built.manifest));
|
|
139
|
+
return { manifest: built.manifest, issues, changed, written };
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=flows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flows.js","sourceRoot":"","sources":["../src/flows.ts"],"names":[],"mappings":"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"}
|
package/dist/format.d.ts
ADDED
package/dist/format.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const plural = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`;
|
|
2
|
+
/** Plain-language report for people. `--json` prints the ValidationReport instead. */
|
|
3
|
+
export function formatResult(r, success = "All good: the prototype follows the design contract.") {
|
|
4
|
+
const errors = r.issues.filter((i) => i.severity === "error").length;
|
|
5
|
+
const warnings = r.issues.length - errors;
|
|
6
|
+
if (r.issues.length === 0)
|
|
7
|
+
return success;
|
|
8
|
+
const lines = [];
|
|
9
|
+
lines.push(errors
|
|
10
|
+
? `Found ${plural(errors, "problem")}${warnings ? ` and ${plural(warnings, "warning")}` : ""} to fix.`
|
|
11
|
+
: `No problems, but ${plural(warnings, "warning")}:`);
|
|
12
|
+
const byFile = new Map();
|
|
13
|
+
for (const i of r.issues)
|
|
14
|
+
byFile.set(i.file, [...(byFile.get(i.file) ?? []), i]);
|
|
15
|
+
for (const [file, list] of byFile) {
|
|
16
|
+
lines.push("", file);
|
|
17
|
+
for (const i of list) {
|
|
18
|
+
const where = i.line ? `line ${i.line}: ` : "";
|
|
19
|
+
const tag = i.severity === "warning" ? "(warning) " : "";
|
|
20
|
+
lines.push(` ${tag}${where}${i.message}`);
|
|
21
|
+
if (i.suggestion)
|
|
22
|
+
lines.push(` suggested: ${i.suggestion}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return lines.join("\n");
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,IAAY,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;AAEhF,sFAAsF;AACtF,MAAM,UAAU,YAAY,CAAC,CAAmB,EAAE,OAAO,GAAG,sDAAsD;IAChH,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;IACrE,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;IAC1C,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IAE1C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CACR,MAAM;QACJ,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU;QACtG,CAAC,CAAC,oBAAoB,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG,CACvD,CAAC;IACF,MAAM,MAAM,GAAG,IAAI,GAAG,EAA2B,CAAC;IAClD,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM;QAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACjF,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QACrB,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/C,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;YACzD,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,GAAG,KAAK,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;YAC3C,IAAI,CAAC,CAAC,UAAU;gBAAE,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
package/dist/gaps.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type Gap } from "@cogitato/contract";
|
|
2
|
+
import { type Project } from "./project.js";
|
|
3
|
+
export interface AddGapOptions {
|
|
4
|
+
kind: Gap["kind"];
|
|
5
|
+
/** What's missing, e.g. "Stepper" or "color.feedback.warning-subtle". */
|
|
6
|
+
name: string;
|
|
7
|
+
/** What the designer was trying to do. */
|
|
8
|
+
context: string;
|
|
9
|
+
screen?: string;
|
|
10
|
+
workaround?: string;
|
|
11
|
+
requestedBy?: string;
|
|
12
|
+
/** For tests. */
|
|
13
|
+
now?: Date;
|
|
14
|
+
}
|
|
15
|
+
export interface AddGapResult {
|
|
16
|
+
gap: Gap;
|
|
17
|
+
/** False when the same open gap was already logged; it's returned instead of a duplicate. */
|
|
18
|
+
created: boolean;
|
|
19
|
+
}
|
|
20
|
+
/** Records something the design needed that the contract doesn't have, in design/contract/gaps.json. */
|
|
21
|
+
export declare function addGap(project: Project, opts: AddGapOptions): AddGapResult;
|
package/dist/gaps.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { kebabCase, validateFormat } from "@cogitato/contract";
|
|
4
|
+
import { KitError } from "./errors.js";
|
|
5
|
+
import { LAYOUT } from "./project.js";
|
|
6
|
+
const FILE = `${LAYOUT.contract}/gaps.json`;
|
|
7
|
+
const SCHEMA = "../../node_modules/@cogitato/contract/schema/gaps.schema.json";
|
|
8
|
+
function gitUser(project) {
|
|
9
|
+
const r = spawnSync("git", ["config", "user.name"], { cwd: project.root, encoding: "utf8" });
|
|
10
|
+
return r.status === 0 && r.stdout.trim() ? r.stdout.trim() : undefined;
|
|
11
|
+
}
|
|
12
|
+
/** Records something the design needed that the contract doesn't have, in design/contract/gaps.json. */
|
|
13
|
+
export function addGap(project, opts) {
|
|
14
|
+
const path = project.abs(FILE);
|
|
15
|
+
let log = { $schema: SCHEMA, gaps: [] };
|
|
16
|
+
if (existsSync(path)) {
|
|
17
|
+
try {
|
|
18
|
+
log = JSON.parse(readFileSync(path, "utf8"));
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
throw new KitError(`${FILE} has a typo in it, so the gap couldn't be added. Ask a developer to fix the file.`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const name = opts.name.trim();
|
|
25
|
+
const same = log.gaps.find((g) => g.status === "open" && g.kind === opts.kind && g.name.toLowerCase() === name.toLowerCase());
|
|
26
|
+
if (same)
|
|
27
|
+
return { gap: same, created: false };
|
|
28
|
+
const slug = kebabCase(name).replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "") || "item";
|
|
29
|
+
const taken = new Set(log.gaps.map((g) => g.id));
|
|
30
|
+
let id = `gap_${slug}`;
|
|
31
|
+
for (let n = 2; taken.has(id); n++)
|
|
32
|
+
id = `gap_${slug}-${n}`;
|
|
33
|
+
const requestedBy = opts.requestedBy ?? gitUser(project);
|
|
34
|
+
const gap = {
|
|
35
|
+
id,
|
|
36
|
+
kind: opts.kind,
|
|
37
|
+
name,
|
|
38
|
+
context: opts.context.trim(),
|
|
39
|
+
...(opts.screen ? { screen: opts.screen } : {}),
|
|
40
|
+
...(opts.workaround?.trim() ? { workaround: opts.workaround.trim() } : {}),
|
|
41
|
+
...(requestedBy ? { requestedBy } : {}),
|
|
42
|
+
status: "open",
|
|
43
|
+
createdAt: (opts.now ?? new Date()).toISOString().replace(/\.\d{3}Z$/, "Z"),
|
|
44
|
+
};
|
|
45
|
+
const next = { ...log, gaps: [...log.gaps, gap] };
|
|
46
|
+
const check = validateFormat("gaps", next, FILE);
|
|
47
|
+
if (!check.ok)
|
|
48
|
+
throw new KitError(`The gap couldn't be recorded: ${check.issues.map((i) => i.message).join(" ")}`);
|
|
49
|
+
writeFileSync(path, JSON.stringify(next, null, 2) + "\n");
|
|
50
|
+
return { gap, created: true };
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=gaps.js.map
|
package/dist/gaps.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gaps.js","sourceRoot":"","sources":["../src/gaps.ts"],"names":[],"mappings":"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"}
|
package/dist/hook.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type DoctorOptions } from "./doctor.js";
|
|
2
|
+
import { type Project } from "./project.js";
|
|
3
|
+
export type HookEvent = "post-edit" | "session-start";
|
|
4
|
+
export interface HookInput {
|
|
5
|
+
hook_event_name?: string;
|
|
6
|
+
cwd?: string;
|
|
7
|
+
tool_name?: string;
|
|
8
|
+
tool_input?: {
|
|
9
|
+
file_path?: string;
|
|
10
|
+
};
|
|
11
|
+
source?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface HookOutput {
|
|
14
|
+
decision?: "block";
|
|
15
|
+
reason?: string;
|
|
16
|
+
systemMessage?: string;
|
|
17
|
+
hookSpecificOutput?: {
|
|
18
|
+
hookEventName: "PostToolUse" | "SessionStart";
|
|
19
|
+
additionalContext?: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export declare const MCP_TOOLS = "list_components, get_component, get_tokens, create_screen, add_state, log_gap, validate, canvas_link, set_status";
|
|
23
|
+
/** Which files the edit hook checks: prototype source outside the kit, and the design/ folder. */
|
|
24
|
+
export declare function checkedByHook(rel: string): boolean;
|
|
25
|
+
/** After Claude writes or edits a file: keep flows.json fresh and send any problems back to Claude. */
|
|
26
|
+
export declare function postEditHook(project: Project, input: HookInput): HookOutput | undefined;
|
|
27
|
+
/** At session start: tell the designer (one line) and Claude (details) if the machine isn't ready. */
|
|
28
|
+
export declare function sessionStartHook(project: Project, opts?: DoctorOptions): Promise<HookOutput>;
|
|
29
|
+
/**
|
|
30
|
+
* Runs a hook from its JSON input. Returns undefined when there's nothing to say (including
|
|
31
|
+
* when the session isn't in a Cogitato prototype at all).
|
|
32
|
+
*/
|
|
33
|
+
export declare function runHook(event: HookEvent, input: HookInput, start?: string): Promise<HookOutput | undefined>;
|
package/dist/hook.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { isAbsolute } from "node:path";
|
|
2
|
+
import { doctor } from "./doctor.js";
|
|
3
|
+
import { exportFlows } from "./export-flows.js";
|
|
4
|
+
import { formatResult } from "./format.js";
|
|
5
|
+
import { LAYOUT, findProject, isKitFile, isScreenFile, sourceFiles } from "./project.js";
|
|
6
|
+
import { readRegistry } from "./registry.js";
|
|
7
|
+
import { validate } from "./validate.js";
|
|
8
|
+
export const MCP_TOOLS = "list_components, get_component, get_tokens, create_screen, add_state, log_gap, validate, canvas_link, set_status";
|
|
9
|
+
const FIX_ADVICE = "Fix these before finishing. If the design needs something the kit doesn't have, use the nearest token or kit component " +
|
|
10
|
+
"and say so, or log a gap with the log_gap tool; don't hardcode values or build your own components.";
|
|
11
|
+
/** Which files the edit hook checks: prototype source outside the kit, and the design/ folder. */
|
|
12
|
+
export function checkedByHook(rel) {
|
|
13
|
+
if (rel.startsWith("..") || isAbsolute(rel))
|
|
14
|
+
return false;
|
|
15
|
+
if (rel.startsWith(`${LAYOUT.design}/`))
|
|
16
|
+
return rel.endsWith(".json") || rel.endsWith(".md");
|
|
17
|
+
return rel.startsWith(`${LAYOUT.src}/`) && /\.(tsx?|css)$/.test(rel) && !rel.endsWith(".d.ts") && !isKitFile(rel);
|
|
18
|
+
}
|
|
19
|
+
/** After Claude writes or edits a file: keep flows.json fresh and send any problems back to Claude. */
|
|
20
|
+
export function postEditHook(project, input) {
|
|
21
|
+
const file = input.tool_input?.file_path;
|
|
22
|
+
if (!file)
|
|
23
|
+
return undefined;
|
|
24
|
+
const rel = project.rel(file);
|
|
25
|
+
if (!checkedByHook(rel))
|
|
26
|
+
return undefined;
|
|
27
|
+
if (rel === LAYOUT.flowsJson) {
|
|
28
|
+
return {
|
|
29
|
+
decision: "block",
|
|
30
|
+
reason: "design/flows.json is generated from the screens and src/flows.ts, so edits to it get overwritten. " +
|
|
31
|
+
"Change src/flows.ts (or the screen's states) instead; the file updates itself after each edit.",
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (isScreenFile(rel) || rel === LAYOUT.flowsTs)
|
|
35
|
+
exportFlows(project);
|
|
36
|
+
const r = validate(project, { files: [rel] });
|
|
37
|
+
if (r.ok && r.issues.length === 0)
|
|
38
|
+
return undefined;
|
|
39
|
+
if (r.ok) {
|
|
40
|
+
return { hookSpecificOutput: { hookEventName: "PostToolUse", additionalContext: `Cogitato check of ${rel}:\n${formatResult(r)}` } };
|
|
41
|
+
}
|
|
42
|
+
return { decision: "block", reason: `Cogitato check of ${rel}: ${formatResult(r)}\n\n${FIX_ADVICE}` };
|
|
43
|
+
}
|
|
44
|
+
/** At session start: tell the designer (one line) and Claude (details) if the machine isn't ready. */
|
|
45
|
+
export async function sessionStartHook(project, opts = {}) {
|
|
46
|
+
const checks = await doctor(project, opts);
|
|
47
|
+
const problems = checks.filter((c) => c.status === "problem");
|
|
48
|
+
const warnings = checks.filter((c) => c.status === "warning");
|
|
49
|
+
const reg = readRegistry(project, sourceFiles(project));
|
|
50
|
+
const states = reg.screens.reduce((n, s) => n + s.fixtures.length, 0);
|
|
51
|
+
const context = [
|
|
52
|
+
`This is a Cogitato prototype: ${reg.screens.length} screen${reg.screens.length === 1 ? "" : "s"}, ${states} state${states === 1 ? "" : "s"}.`,
|
|
53
|
+
"The person here is usually a designer: plain language, never ask them to run commands.",
|
|
54
|
+
`Use the Cogitato MCP tools (${MCP_TOOLS}) instead of reading design/contract files, and the Cogitato skills for building screens and states.`,
|
|
55
|
+
"Every edit is checked automatically and design/flows.json is regenerated after each one, so there's no need to run kit commands yourself.",
|
|
56
|
+
...(problems.length
|
|
57
|
+
? ["", "Setup problems found:", ...problems.map((c) => `- ${c.message}`), "Offer to fix them with the Cogitato setup-machine skill, in plain words."]
|
|
58
|
+
: []),
|
|
59
|
+
...(warnings.length ? ["", "Notes:", ...warnings.map((c) => `- ${c.message}`)] : []),
|
|
60
|
+
].join("\n");
|
|
61
|
+
return {
|
|
62
|
+
...(problems.length
|
|
63
|
+
? { systemMessage: `Cogitato: this prototype isn't ready on this computer yet. ${problems[0].message} Ask Claude to set it up.` }
|
|
64
|
+
: {}),
|
|
65
|
+
hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: context },
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Runs a hook from its JSON input. Returns undefined when there's nothing to say (including
|
|
70
|
+
* when the session isn't in a Cogitato prototype at all).
|
|
71
|
+
*/
|
|
72
|
+
export async function runHook(event, input, start = input.cwd ?? process.cwd()) {
|
|
73
|
+
const project = findProject(start);
|
|
74
|
+
if (!project)
|
|
75
|
+
return undefined;
|
|
76
|
+
return event === "post-edit" ? postEditHook(project, input) : sessionStartHook(project);
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=hook.js.map
|
package/dist/hook.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook.js","sourceRoot":"","sources":["../src/hook.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { DEFAULT_PORT, doctor, formatDoctor, isServerUp, type CheckStatus, type DoctorCheck, type DoctorOptions } from "./doctor.js";
|
|
2
|
+
export { exportFlows, type ExportOptions } from "./export-flows.js";
|
|
3
|
+
export { buildManifest, keptStatus, sameManifest, serializeManifest, type ExportResult } from "./flows.js";
|
|
4
|
+
export { formatResult } from "./format.js";
|
|
5
|
+
export { KIT_PATH, preview, type PreviewOptions, type PreviewResult } from "./preview.js";
|
|
6
|
+
export { LAYOUT, findProject, projectAt, readContract, sourceFiles, type ContractView, type Project } from "./project.js";
|
|
7
|
+
export { ID_PATTERNS, humanize, readFlows, readRegistry, readScreen, type Registry, type ScreenEntry } from "./registry.js";
|
|
8
|
+
export { checkCssValue } from "./rules/css-values.js";
|
|
9
|
+
export { validate, type ValidateOptions } from "./validate.js";
|
|
10
|
+
export { KitError } from "./errors.js";
|
|
11
|
+
export { addGap, type AddGapOptions, type AddGapResult } from "./gaps.js";
|
|
12
|
+
export { MCP_TOOLS, checkedByHook, postEditHook, runHook, sessionStartHook, type HookEvent, type HookInput, type HookOutput } from "./hook.js";
|
|
13
|
+
export { CANVAS_PATH, branchSlug, canvasLink, previewLink, stateLink } from "./links.js";
|
|
14
|
+
export { SNAPSHOT_VIEWPORT, snapshotFile, snapshotManifest, takeSnapshots, type SnapshotOptions, type SnapshotResult } from "./snapshots.js";
|
|
15
|
+
export { FRAME_STATUSES, setStatus, statusLabel, type FrameStatusValue } from "./status.js";
|
|
16
|
+
export { describeChanges, saveVersion, type SaveOptions, type SaveResult } from "./save.js";
|
|
17
|
+
export { addEdge, addState, createScreen, type AddEdgeOptions, type AddStateOptions, type CreateScreenOptions, type ScaffoldResult, } from "./scaffold.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Library entry. Hooks, skills and the kit MCP server call these; they don't reimplement them.
|
|
2
|
+
export { DEFAULT_PORT, doctor, formatDoctor, isServerUp } from "./doctor.js";
|
|
3
|
+
export { exportFlows } from "./export-flows.js";
|
|
4
|
+
export { buildManifest, keptStatus, sameManifest, serializeManifest } from "./flows.js";
|
|
5
|
+
export { formatResult } from "./format.js";
|
|
6
|
+
export { KIT_PATH, preview } from "./preview.js";
|
|
7
|
+
export { LAYOUT, findProject, projectAt, readContract, sourceFiles } from "./project.js";
|
|
8
|
+
export { ID_PATTERNS, humanize, readFlows, readRegistry, readScreen } from "./registry.js";
|
|
9
|
+
export { checkCssValue } from "./rules/css-values.js";
|
|
10
|
+
export { validate } from "./validate.js";
|
|
11
|
+
export { KitError } from "./errors.js";
|
|
12
|
+
export { addGap } from "./gaps.js";
|
|
13
|
+
export { MCP_TOOLS, checkedByHook, postEditHook, runHook, sessionStartHook } from "./hook.js";
|
|
14
|
+
export { CANVAS_PATH, branchSlug, canvasLink, previewLink, stateLink } from "./links.js";
|
|
15
|
+
export { SNAPSHOT_VIEWPORT, snapshotFile, snapshotManifest, takeSnapshots } from "./snapshots.js";
|
|
16
|
+
export { FRAME_STATUSES, setStatus, statusLabel } from "./status.js";
|
|
17
|
+
export { describeChanges, saveVersion } from "./save.js";
|
|
18
|
+
export { addEdge, addState, createScreen, } from "./scaffold.js";
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAA0D,MAAM,aAAa,CAAC;AACrI,OAAO,EAAE,WAAW,EAAsB,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAqB,MAAM,YAAY,CAAC;AAC3G,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,OAAO,EAA2C,MAAM,cAAc,CAAC;AAC1F,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAmC,MAAM,cAAc,CAAC;AAC1H,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAmC,MAAM,eAAe,CAAC;AAC5H,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAwB,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,MAAM,EAAyC,MAAM,WAAW,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,OAAO,EAAE,gBAAgB,EAAmD,MAAM,WAAW,CAAC;AAC/I,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAA6C,MAAM,gBAAgB,CAAC;AAC7I,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,WAAW,EAAyB,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,eAAe,EAAE,WAAW,EAAqC,MAAM,WAAW,CAAC;AAC5F,OAAO,EACL,OAAO,EACP,QAAQ,EACR,YAAY,GAKb,MAAM,eAAe,CAAC"}
|
package/dist/issue.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Issue } from "@cogitato/contract";
|
|
2
|
+
import ts from "typescript";
|
|
3
|
+
export type { Issue };
|
|
4
|
+
/** Issue at a position in a TypeScript source file. */
|
|
5
|
+
export declare function issueAt(code: string, sf: ts.SourceFile, node: ts.Node, message: string, extra?: {
|
|
6
|
+
severity?: Issue["severity"];
|
|
7
|
+
suggestion?: string;
|
|
8
|
+
}): Issue;
|
|
9
|
+
export declare function parseSource(file: string, text: string): ts.SourceFile;
|
|
10
|
+
/** Text of a string literal or a template without substitutions; undefined for anything computed. */
|
|
11
|
+
export declare function literalText(node: ts.Node | undefined): string | undefined;
|
|
12
|
+
/** Name of an object literal property when it's written as plain text. */
|
|
13
|
+
export declare function propertyName(name: ts.PropertyName): string | undefined;
|
|
14
|
+
/** The value expression of property `key` in an object literal, if it's a plain `key: value` assignment. */
|
|
15
|
+
export declare function getProperty(obj: ts.ObjectLiteralExpression, key: string): ts.PropertyAssignment | undefined;
|
|
16
|
+
/** Calls to `name(...)` (or `x.name(...)`) anywhere in the file. */
|
|
17
|
+
export declare function findCalls(sf: ts.SourceFile, name: string): ts.CallExpression[];
|
package/dist/issue.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
/** Issue at a position in a TypeScript source file. */
|
|
3
|
+
export function issueAt(code, sf, node, message, extra = {}) {
|
|
4
|
+
const { line, character } = sf.getLineAndCharacterOfPosition(node.getStart(sf));
|
|
5
|
+
return {
|
|
6
|
+
code,
|
|
7
|
+
severity: extra.severity ?? "error",
|
|
8
|
+
file: sf.fileName,
|
|
9
|
+
path: "",
|
|
10
|
+
line: line + 1,
|
|
11
|
+
column: character + 1,
|
|
12
|
+
message,
|
|
13
|
+
...(extra.suggestion !== undefined ? { suggestion: extra.suggestion } : {}),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function parseSource(file, text) {
|
|
17
|
+
const kind = file.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
|
|
18
|
+
return ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true, kind);
|
|
19
|
+
}
|
|
20
|
+
/** Text of a string literal or a template without substitutions; undefined for anything computed. */
|
|
21
|
+
export function literalText(node) {
|
|
22
|
+
if (!node)
|
|
23
|
+
return undefined;
|
|
24
|
+
if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node))
|
|
25
|
+
return node.text;
|
|
26
|
+
if (ts.isParenthesizedExpression(node) || ts.isAsExpression(node) || ts.isSatisfiesExpression(node)) {
|
|
27
|
+
return literalText(node.expression);
|
|
28
|
+
}
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
/** Name of an object literal property when it's written as plain text. */
|
|
32
|
+
export function propertyName(name) {
|
|
33
|
+
if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name) || ts.isNoSubstitutionTemplateLiteral(name)) {
|
|
34
|
+
return name.text;
|
|
35
|
+
}
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
/** The value expression of property `key` in an object literal, if it's a plain `key: value` assignment. */
|
|
39
|
+
export function getProperty(obj, key) {
|
|
40
|
+
for (const p of obj.properties) {
|
|
41
|
+
if (ts.isPropertyAssignment(p) && propertyName(p.name) === key)
|
|
42
|
+
return p;
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
/** Calls to `name(...)` (or `x.name(...)`) anywhere in the file. */
|
|
47
|
+
export function findCalls(sf, name) {
|
|
48
|
+
const out = [];
|
|
49
|
+
const visit = (node) => {
|
|
50
|
+
if (ts.isCallExpression(node)) {
|
|
51
|
+
const callee = node.expression;
|
|
52
|
+
const calleeName = ts.isIdentifier(callee)
|
|
53
|
+
? callee.text
|
|
54
|
+
: ts.isPropertyAccessExpression(callee)
|
|
55
|
+
? callee.name.text
|
|
56
|
+
: undefined;
|
|
57
|
+
if (calleeName === name)
|
|
58
|
+
out.push(node);
|
|
59
|
+
}
|
|
60
|
+
ts.forEachChild(node, visit);
|
|
61
|
+
};
|
|
62
|
+
visit(sf);
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=issue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issue.js","sourceRoot":"","sources":["../src/issue.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,YAAY,CAAC;AAI5B,uDAAuD;AACvD,MAAM,UAAU,OAAO,CACrB,IAAY,EACZ,EAAiB,EACjB,IAAa,EACb,OAAe,EACf,QAA+D,EAAE;IAEjE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,6BAA6B,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;IAChF,OAAO;QACL,IAAI;QACJ,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,OAAO;QACnC,IAAI,EAAE,EAAE,CAAC,QAAQ;QACjB,IAAI,EAAE,EAAE;QACR,IAAI,EAAE,IAAI,GAAG,CAAC;QACd,MAAM,EAAE,SAAS,GAAG,CAAC;QACrB,OAAO;QACP,GAAG,CAAC,KAAK,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5E,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,IAAY;IACpD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;IAC1E,OAAO,EAAE,CAAC,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAC7E,CAAC;AAED,qGAAqG;AACrG,MAAM,UAAU,WAAW,CAAC,IAAyB;IACnD,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,IAAI,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,+BAA+B,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,IAAI,CAAC;IAC3F,IAAI,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC;QACpG,OAAO,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,YAAY,CAAC,IAAqB;IAChD,IAAI,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,+BAA+B,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/H,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,4GAA4G;AAC5G,MAAM,UAAU,WAAW,CAAC,GAA+B,EAAE,GAAW;IACtE,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;QAC/B,IAAI,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG;YAAE,OAAO,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,SAAS,CAAC,EAAiB,EAAE,IAAY;IACvD,MAAM,GAAG,GAAwB,EAAE,CAAC;IACpC,MAAM,KAAK,GAAG,CAAC,IAAa,EAAE,EAAE;QAC9B,IAAI,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC;YAC/B,MAAM,UAAU,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC;gBACxC,CAAC,CAAC,MAAM,CAAC,IAAI;gBACb,CAAC,CAAC,EAAE,CAAC,0BAA0B,CAAC,MAAM,CAAC;oBACrC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI;oBAClB,CAAC,CAAC,SAAS,CAAC;YAChB,IAAI,UAAU,KAAK,IAAI;gBAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1C,CAAC;QACD,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC/B,CAAC,CAAC;IACF,KAAK,CAAC,EAAE,CAAC,CAAC;IACV,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/links.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type Project } from "./project.js";
|
|
2
|
+
export declare const CANVAS_PATH = "/__canvas";
|
|
3
|
+
/**
|
|
4
|
+
* Local address of a screen state, like http://localhost:5173/checkout/payment?fixture=card-declined.
|
|
5
|
+
* `node` is "{screen id}.{state}" or just a screen id (its default state).
|
|
6
|
+
*/
|
|
7
|
+
export declare function stateLink(project: Project, node: string, port?: number): string;
|
|
8
|
+
/** Local canvas, opened on one state's frame. */
|
|
9
|
+
export declare function canvasLink(project: Project, node: string, port?: number): string;
|
|
10
|
+
/** Netlify's form of a branch name in branch-deploy addresses: "design/sam-0102" -> "design-sam-0102". */
|
|
11
|
+
export declare function branchSlug(branch: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Hosted canvas for a branch, from `"kit": { "previewUrl": "https://{branch}--site.netlify.app" }`
|
|
14
|
+
* in the prototype's package.json. Undefined when the prototype has no hosting set up.
|
|
15
|
+
*/
|
|
16
|
+
export declare function previewLink(project: Project, branch: string, node?: string): string | undefined;
|