ketatlas 0.1.0 → 0.2.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/CHANGELOG.md +18 -2
- package/LICENSE +1 -1
- package/NOTICE.md +1 -1
- package/README.md +46 -33
- package/bin/audit.js +8 -0
- package/bin/ketatlas.js +56 -2
- package/bin/progress.js +120 -0
- package/bin/server.js +2 -1
- package/bin/viewer.js +10 -2
- package/docs/agent-mockups.md +85 -0
- package/docs/architecture.md +11 -1
- package/docs/cli.md +7 -1
- package/docs/configuration.md +4 -0
- package/docs/integration.md +4 -0
- package/docs/migration.md +2 -1
- package/docs/progress.md +83 -0
- package/docs/releasing.md +45 -16
- package/package.json +10 -7
- package/progress.schema.json +130 -0
- package/skills/ketatlas/SKILL.md +143 -0
- package/src/index.d.ts +66 -0
- package/src/index.js +55 -2
- package/src/layout.js +1 -1
- package/src/progress-ui.js +251 -0
- package/src/progress.js +177 -0
- package/src/template.js +1 -1
- package/styles/ketatlas.css +294 -0
- package/templates/basic/README.md +2 -2
- package/templates/basic/progress.schema.json +130 -0
- package/templates/process/README.md +2 -2
- package/templates/process/progress.schema.json +130 -0
- package/templates/web/README.md +2 -2
- package/templates/web/progress.schema.json +130 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
- Track delivery per screen in a separate progress JSON, with acceptance checks, blockers, ownership, task references and PR/test/release evidence.
|
|
6
|
+
- Review all screens with filters and shared map badges; edit progress using the local viewer or revision-checked CLI.
|
|
7
|
+
- Refuse stale writes and unsupported verification claims; keep static hosting read-only and existing version 1 workflows compatible.
|
|
8
|
+
- Audit progress references, provide a public schema/API, and test browser editing, concurrency and packaged installation.
|
|
9
|
+
|
|
10
|
+
## 0.1.1 — 2026-09-04
|
|
11
|
+
|
|
12
|
+
- Publish the tested archive through an absolute file path; support guarded retries after a CI workflow fix.
|
|
13
|
+
|
|
14
|
+
- Clarify the consumer contract: JSON, product screens, assets, and docs only; verify global and npx usage without project manifests or dependencies.
|
|
15
|
+
|
|
16
|
+
- Portable KetAtlas agent skill and a product-brief workflow for generating compatible interactive HTML mockups.
|
|
17
|
+
- Automatically publish verified stable version increases from `develop`, with duplicate-release protection and npm provenance.
|
|
18
|
+
|
|
19
|
+
## 0.1.0 — 2026-09-04
|
|
4
20
|
|
|
5
21
|
- Standalone `ketatlas scaffold`, `serve <atlas.json>`, `audit`, and `validate` commands.
|
|
6
22
|
- Basic, web and screenless process templates with a local configuration schema.
|
|
@@ -10,4 +26,4 @@
|
|
|
10
26
|
- Canonical KetJS design system with pinned provenance and offline assets.
|
|
11
27
|
- Static audits, CLI/server tests, browser evidence and packed-install verification.
|
|
12
28
|
|
|
13
|
-
|
|
29
|
+
Published to [npm](https://www.npmjs.com/package/ketatlas/v/0.1.0).
|
package/LICENSE
CHANGED
package/NOTICE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Third-party notices
|
|
2
2
|
|
|
3
|
-
KetAtlas is maintained by
|
|
3
|
+
KetAtlas is maintained by KET VIET JSC, VN under the MIT license.
|
|
4
4
|
|
|
5
5
|
- The viewer originated from KétSuite's HTML flow-map prototype, then was extracted into this independent package. No mobile app code or business data is bundled.
|
|
6
6
|
- Default tokens and UI primitives: `@ketvietlab/design-system` from [KetJS](https://github.com/ketvietlab/ketjs), MIT. Exact source revision and file hashes are recorded in `assets/design-system.lock.json`. Generated output only adapts root selectors to a Shadow DOM host; token values are unchanged. See `assets/KETJS-LICENSE`.
|
package/README.md
CHANGED
|
@@ -6,56 +6,48 @@ Turn a JSON file and your existing HTML screens into a canvas you can drag, zoom
|
|
|
6
6
|
|
|
7
7
|
KetAtlas has an English UI, zero runtime npm dependencies, and no build step. Node.js **22+** is needed for the CLI. Viewers use native ES modules and run on an HTTP server.
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Demo
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
npm ci
|
|
15
|
-
npm run dev
|
|
16
|
-
```
|
|
11
|
+
See a mobile workflow map in action: explore connected screens and try the HTML prototype.
|
|
12
|
+
|
|
13
|
+
https://github.com/user-attachments/assets/13f24fc8-7b8e-4bda-9e02-364c120ee163
|
|
17
14
|
|
|
18
|
-
|
|
15
|
+
## Run without a project install
|
|
19
16
|
|
|
20
|
-
|
|
17
|
+
[KetAtlas is available on npm](https://www.npmjs.com/package/ketatlas). Use Node.js 22+ and run it from any directory:
|
|
21
18
|
|
|
22
19
|
```sh
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
npx --yes ketatlas@0.2.0 scaffold my-atlas --template web
|
|
21
|
+
npx --yes ketatlas@0.2.0 serve my-atlas/atlas.json
|
|
22
|
+
npx --yes ketatlas@0.2.0 audit my-atlas/atlas.json --strict
|
|
26
23
|
```
|
|
27
24
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
## Run through npx
|
|
31
|
-
|
|
32
|
-
Run immediately from a local checkout, including before the first push or npm release:
|
|
25
|
+
Or install the CLI once for your user account:
|
|
33
26
|
|
|
34
27
|
```sh
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
28
|
+
npm install --global ketatlas@0.2.0
|
|
29
|
+
ketatlas scaffold my-atlas
|
|
30
|
+
ketatlas serve my-atlas/atlas.json
|
|
31
|
+
ketatlas audit my-atlas/atlas.json --strict
|
|
38
32
|
```
|
|
39
33
|
|
|
40
|
-
|
|
34
|
+
The consumer folder contains `atlas.json`, its schema, product HTML/CSS/JavaScript, local assets, and documentation. It needs no `package.json`, lockfile, `node_modules`, build step, or copy of the viewer. The CLI supplies scaffold, serving, and static audit from its own installation. `audit` leaves project files unchanged unless an output file is explicitly requested. Viewing with `serve` does not write; explicit **Save progress** writes the sibling progress file. Use `--read-only` to disable editing.
|
|
41
35
|
|
|
42
|
-
|
|
36
|
+
Pin the version in run commands or the global installation for reproducible team workflows. Product scripts implement mock screen interactions; they are authored content, not a local installation of KetAtlas. Framework tooling and tests stay in the KetAtlas repository.
|
|
43
37
|
|
|
44
|
-
|
|
45
|
-
npx --yes --package=github:ketvietlab/ketatlas ketatlas scaffold my-atlas
|
|
46
|
-
npx --yes --package=github:ketvietlab/ketatlas ketatlas serve my-atlas/atlas.json
|
|
47
|
-
npx --yes --package=github:ketvietlab/ketatlas ketatlas audit my-atlas/atlas.json
|
|
48
|
-
```
|
|
38
|
+
Edit the JSON and screen files, then refresh the browser. The default viewer address is **http://127.0.0.1:4178**.
|
|
49
39
|
|
|
50
|
-
|
|
40
|
+
## Create mockups with an agent
|
|
41
|
+
|
|
42
|
+
Install the KetAtlas skill in your product project:
|
|
51
43
|
|
|
52
44
|
```sh
|
|
53
|
-
npx
|
|
54
|
-
npx ketatlas serve my-atlas/atlas.json
|
|
55
|
-
npx ketatlas audit my-atlas/atlas.json --strict
|
|
45
|
+
npx skills add ketvietlab/ketatlas --skill ketatlas
|
|
56
46
|
```
|
|
57
47
|
|
|
58
|
-
|
|
48
|
+
Ask your agent to use the skill with a product brief: requested flows, target platforms, design references, and output directory. The agent creates actual HTML screens, a version 1 `atlas.json`, and run instructions, then audits the result.
|
|
49
|
+
|
|
50
|
+
See [Agent mockups](docs/agent-mockups.md) for installation options, a ready-to-use request, and a reusable brief template. Agents without skill support can read the [single skill file](skills/ketatlas/SKILL.md) directly.
|
|
59
51
|
|
|
60
52
|
## One file describes the journey
|
|
61
53
|
|
|
@@ -83,6 +75,10 @@ The repository does not imply an npm release. Package installation is tested fro
|
|
|
83
75
|
|
|
84
76
|
URLs resolve relative to the JSON file. Nodes default to a left-to-right row. Set `column` and `row` for branches; set each screen's `viewport` for mobile or desktop dimensions. Reuse a screen in many flows without duplicating its HTML.
|
|
85
77
|
|
|
78
|
+
## Track delivery
|
|
79
|
+
|
|
80
|
+
Open **Screens** to filter screen progress, review blockers and edit acceptance checks with PR/test evidence. Records live in a sibling `atlas.progress.json` tracked in Git; repeated nodes share one screen record. A merged PR is not a verified screen. Local saves detect concurrent edits; static hosting is read-only. See [Screen progress](docs/progress.md) for the contract, CLI and embedding API.
|
|
81
|
+
|
|
86
82
|
## Commands
|
|
87
83
|
|
|
88
84
|
| Command | Purpose |
|
|
@@ -109,6 +105,19 @@ Give the container a height. Ship `src/`, `styles/`, and `assets/` together. Sha
|
|
|
109
105
|
|
|
110
106
|
## Explore and contribute
|
|
111
107
|
|
|
108
|
+
To develop KetAtlas itself, clone this repository and install its development dependencies:
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
git clone git@github.com:ketvietlab/ketatlas.git
|
|
112
|
+
cd ketatlas
|
|
113
|
+
npm ci
|
|
114
|
+
npm run dev
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The playground includes mobile sign-in, desktop approval, and a fulfilment process. These development dependencies are not required in consumer projects. To try an unpublished checkout, use `npx --yes --package ~/dev/ketatlas ketatlas serve /path/to/my-atlas/atlas.json`.
|
|
118
|
+
|
|
119
|
+
Stable version increases merged into `develop` are automatically published after CI verifies the package. See [Releasing](docs/releasing.md).
|
|
120
|
+
|
|
112
121
|
- [Authoring guide](docs/authoring.md): screens, processes, branching, reuse, and viewport sizes.
|
|
113
122
|
- [Configuration reference](docs/configuration.md): schema and defaults.
|
|
114
123
|
- [CLI and audit](docs/cli.md): commands, exit codes, and audit boundaries.
|
|
@@ -127,4 +136,8 @@ npm run test:package
|
|
|
127
136
|
|
|
128
137
|
Audit is static analysis. It does not execute product code or prove that native apps, external services, or embedded pages behave correctly. Arrows describe the authored workflow; the embedded HTML retains its own interactions.
|
|
129
138
|
|
|
130
|
-
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
KetAtlas is a project of **KET VIET JSC, VN**, distributed under the [MIT License](LICENSE).
|
|
142
|
+
|
|
143
|
+
Copyright (c) 2026 KET VIET JSC, VN. See [third-party notices](NOTICE.md) for bundled dependencies.
|
package/bin/audit.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readProgress, progressPath } from "./progress.js";
|
|
1
2
|
import { readFile, realpath, stat } from "node:fs/promises";
|
|
2
3
|
import { resolve, dirname, relative, sep, extname } from "node:path";
|
|
3
4
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
@@ -93,6 +94,13 @@ export async function auditAtlas(file, { root: rootOption } = {}) {
|
|
|
93
94
|
for (const f of config.flows)
|
|
94
95
|
for (const n of f.nodes) if (n.url) await inspect(n.url, absolute, `node:${f.id}/${n.id}`);
|
|
95
96
|
}
|
|
97
|
+
if (result.valid) {
|
|
98
|
+
try {
|
|
99
|
+
await readProgress(progressPath(absolute), config);
|
|
100
|
+
} catch (e) {
|
|
101
|
+
errors.push({ path: "progress", message: e.message });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
96
104
|
for (const url of remote)
|
|
97
105
|
warnings.push({ path: "remote", message: `Remote URL not fetched: ${url}` });
|
|
98
106
|
const flows = Array.isArray(config?.flows) ? config.flows : [];
|
package/bin/ketatlas.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { progressPath, readProgress, saveProgress } from "./progress.js";
|
|
3
|
+
import { summarizeProgress } from "../src/progress.js";
|
|
2
4
|
import { readFile, readdir, mkdir, cp, writeFile, stat } from "node:fs/promises";
|
|
3
5
|
import { resolve, dirname, join } from "node:path";
|
|
4
6
|
import { fileURLToPath } from "node:url";
|
|
@@ -13,6 +15,8 @@ const help = `KetAtlas — scaffold, serve, and audit HTML workflow maps
|
|
|
13
15
|
ketatlas serve <atlas.json> [--port 4178] [--root directory]
|
|
14
16
|
ketatlas audit <atlas.json> [--root directory] [--json] [--strict]
|
|
15
17
|
ketatlas validate <atlas.json>
|
|
18
|
+
ketatlas progress <atlas.json> [--json] [--init]
|
|
19
|
+
ketatlas progress <atlas.json> --set <screen-id> --record <record.json> --expect <revision>
|
|
16
20
|
ketatlas --version
|
|
17
21
|
|
|
18
22
|
Examples:
|
|
@@ -118,8 +122,58 @@ async function main(args) {
|
|
|
118
122
|
);
|
|
119
123
|
return;
|
|
120
124
|
}
|
|
125
|
+
if (command === "progress") {
|
|
126
|
+
const { target, options } = parse(rest, {
|
|
127
|
+
json: "boolean",
|
|
128
|
+
init: "boolean",
|
|
129
|
+
set: "string",
|
|
130
|
+
record: "string",
|
|
131
|
+
expect: "string",
|
|
132
|
+
});
|
|
133
|
+
const file = resolve(target),
|
|
134
|
+
atlas = JSON.parse(await readFile(file, "utf8"));
|
|
135
|
+
const valid = validateAtlas(atlas);
|
|
136
|
+
if (!valid.valid) throw new Error(valid.errors.map((e) => e.message).join("; "));
|
|
137
|
+
const path = progressPath(file);
|
|
138
|
+
let result = await readProgress(path, atlas);
|
|
139
|
+
if (options.init) {
|
|
140
|
+
if (options.set || options.record || options.expect)
|
|
141
|
+
throw new Error("Use --init separately from an update.");
|
|
142
|
+
if (result.revision !== "missing") throw new Error("Progress already exists.");
|
|
143
|
+
result = await saveProgress(path, file, "missing", (data) => {
|
|
144
|
+
for (const s of atlas.screens || [])
|
|
145
|
+
Object.defineProperty(data.screens, s.id, {
|
|
146
|
+
value: { status: "unassessed" },
|
|
147
|
+
enumerable: true,
|
|
148
|
+
});
|
|
149
|
+
return data;
|
|
150
|
+
});
|
|
151
|
+
} else if (options.set || options.record || options.expect) {
|
|
152
|
+
if (!options.set || !options.record || !options.expect)
|
|
153
|
+
throw new Error("Updates need --set, --record and --expect from progress --json.");
|
|
154
|
+
const record = JSON.parse(await readFile(resolve(options.record), "utf8"));
|
|
155
|
+
result = await saveProgress(path, file, options.expect, (data) => {
|
|
156
|
+
Object.defineProperty(data.screens, options.set, {
|
|
157
|
+
value: { ...record, updatedAt: new Date().toISOString() },
|
|
158
|
+
enumerable: true,
|
|
159
|
+
});
|
|
160
|
+
return data;
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
const summary = summarizeProgress(result.data, atlas.screens || []);
|
|
164
|
+
console.log(
|
|
165
|
+
options.json
|
|
166
|
+
? JSON.stringify({ ...result, summary }, null, 2)
|
|
167
|
+
: `${summary.total} screens · ${summary.counts.verified} verified · ${summary.blocked} blocked\nRevision: ${result.revision}\n${path}`,
|
|
168
|
+
);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
121
171
|
if (command === "serve") {
|
|
122
|
-
const { target, options } = parse(rest, {
|
|
172
|
+
const { target, options } = parse(rest, {
|
|
173
|
+
port: "string",
|
|
174
|
+
root: "string",
|
|
175
|
+
"read-only": "boolean",
|
|
176
|
+
}),
|
|
123
177
|
port = Number(options.port || 4178);
|
|
124
178
|
if (!Number.isInteger(port) || port < 1 || port > 65535)
|
|
125
179
|
throw new Error("Port must be 1–65535.");
|
|
@@ -128,7 +182,7 @@ async function main(args) {
|
|
|
128
182
|
throw new Error("--root is only needed when serving an atlas JSON file.");
|
|
129
183
|
const server = directory
|
|
130
184
|
? await serve(target, { port })
|
|
131
|
-
: await serveAtlas(target, { port, root: options.root });
|
|
185
|
+
: await serveAtlas(target, { port, root: options.root, readOnly: options["read-only"] });
|
|
132
186
|
console.log(
|
|
133
187
|
`KetAtlas: http://127.0.0.1:${server.address().port}\nServing ${resolve(target)}\nPress Ctrl+C to stop.`,
|
|
134
188
|
);
|
package/bin/progress.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { readFile, writeFile, rename, unlink, open, lstat } from "node:fs/promises";
|
|
2
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { emptyProgress, requireProgress } from "../src/progress.js";
|
|
5
|
+
export const progressPath = (file) => file.replace(/\.json$/i, "") + ".progress.json";
|
|
6
|
+
const hash = (text) => createHash("sha256").update(text).digest("hex");
|
|
7
|
+
export async function readProgress(file, atlas) {
|
|
8
|
+
try {
|
|
9
|
+
if ((await lstat(file)).isSymbolicLink())
|
|
10
|
+
throw new Error("Progress file must not be a symlink.");
|
|
11
|
+
const text = await readFile(file, "utf8");
|
|
12
|
+
return { data: requireProgress(JSON.parse(text), atlas), revision: hash(text) };
|
|
13
|
+
} catch (e) {
|
|
14
|
+
if (e.code !== "ENOENT") throw e;
|
|
15
|
+
return { data: emptyProgress(), revision: "missing" };
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Shared by the CLI and local editor. One lock and content revision prevent stale writes. */
|
|
19
|
+
export async function saveProgress(file, atlasFile, expected, change) {
|
|
20
|
+
file = resolve(file);
|
|
21
|
+
let lock;
|
|
22
|
+
try {
|
|
23
|
+
lock = await open(file + ".lock", "wx");
|
|
24
|
+
} catch (e) {
|
|
25
|
+
if (e.code === "EEXIST")
|
|
26
|
+
throw Object.assign(new Error("Another writer is saving. Reload and retry."), {
|
|
27
|
+
status: 409,
|
|
28
|
+
});
|
|
29
|
+
throw e;
|
|
30
|
+
}
|
|
31
|
+
const temp = file + "." + randomUUID() + ".tmp";
|
|
32
|
+
try {
|
|
33
|
+
const atlas = JSON.parse(await readFile(atlasFile, "utf8"));
|
|
34
|
+
const current = await readProgress(file, atlas);
|
|
35
|
+
if (!expected || expected !== current.revision)
|
|
36
|
+
throw Object.assign(
|
|
37
|
+
new Error(
|
|
38
|
+
"Progress changed since it was loaded. Reload before saving; your draft is still visible.",
|
|
39
|
+
),
|
|
40
|
+
{ status: 409 },
|
|
41
|
+
);
|
|
42
|
+
const data = requireProgress(change(structuredClone(current.data)), atlas);
|
|
43
|
+
const text = JSON.stringify(data, null, 2) + "\n";
|
|
44
|
+
await writeFile(temp, text, { flag: "wx" });
|
|
45
|
+
if ((await readProgress(file, atlas)).revision !== current.revision)
|
|
46
|
+
throw Object.assign(new Error("Progress changed during saving. Reload and retry."), {
|
|
47
|
+
status: 409,
|
|
48
|
+
});
|
|
49
|
+
await rename(temp, file);
|
|
50
|
+
return { data, revision: hash(text) };
|
|
51
|
+
} finally {
|
|
52
|
+
await unlink(temp).catch(() => {});
|
|
53
|
+
await lock.close();
|
|
54
|
+
await unlink(file + ".lock");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export function progressHandler(file, atlasFile, token, editable) {
|
|
58
|
+
const path = progressPath(file);
|
|
59
|
+
return async (req, res) => {
|
|
60
|
+
if (new URL(req.url, "http://localhost").pathname !== "/__ketatlas__/progress") return false;
|
|
61
|
+
const reply = (status, data) => {
|
|
62
|
+
res.writeHead(status, { "Content-Type": "application/json", "Cache-Control": "no-store" });
|
|
63
|
+
res.end(JSON.stringify(data));
|
|
64
|
+
};
|
|
65
|
+
try {
|
|
66
|
+
if (req.method === "GET") {
|
|
67
|
+
reply(200, {
|
|
68
|
+
...(await readProgress(path, JSON.parse(await readFile(atlasFile, "utf8")))),
|
|
69
|
+
editable,
|
|
70
|
+
});
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
if (req.method !== "PUT") {
|
|
74
|
+
reply(405, { error: "Method not allowed" });
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
const origin = `http://${req.headers.host}`;
|
|
78
|
+
if (
|
|
79
|
+
!editable ||
|
|
80
|
+
req.headers.origin !== origin ||
|
|
81
|
+
req.headers["x-ketatlas-token"] !== token ||
|
|
82
|
+
!req.headers["content-type"]?.startsWith("application/json")
|
|
83
|
+
) {
|
|
84
|
+
reply(403, { error: "Progress writes require the local editor." });
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
let text = "",
|
|
88
|
+
size = 0;
|
|
89
|
+
for await (const chunk of req) {
|
|
90
|
+
size += chunk.length;
|
|
91
|
+
if (size > 1024 * 1024) {
|
|
92
|
+
reply(413, { error: "Progress update is too large." });
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
text += chunk;
|
|
96
|
+
}
|
|
97
|
+
const body = JSON.parse(text);
|
|
98
|
+
if (
|
|
99
|
+
typeof body.screenId !== "string" ||
|
|
100
|
+
!body.record ||
|
|
101
|
+
typeof body.record !== "object" ||
|
|
102
|
+
Array.isArray(body.record)
|
|
103
|
+
)
|
|
104
|
+
throw new Error("Expected a screen ID and record.");
|
|
105
|
+
const result = await saveProgress(path, atlasFile, req.headers["if-match"], (data) => {
|
|
106
|
+
Object.defineProperty(data.screens, body.screenId, {
|
|
107
|
+
value: { ...body.record, updatedAt: new Date().toISOString() },
|
|
108
|
+
enumerable: true,
|
|
109
|
+
writable: true,
|
|
110
|
+
configurable: true,
|
|
111
|
+
});
|
|
112
|
+
return data;
|
|
113
|
+
});
|
|
114
|
+
reply(200, { ...result, editable });
|
|
115
|
+
} catch (e) {
|
|
116
|
+
reply(e.status || 400, { error: e.message });
|
|
117
|
+
}
|
|
118
|
+
return true;
|
|
119
|
+
};
|
|
120
|
+
}
|
package/bin/server.js
CHANGED
|
@@ -21,7 +21,7 @@ const within = (root, path) => {
|
|
|
21
21
|
/** Local static preview only. Resolves symlinks before checking the root boundary. */
|
|
22
22
|
export async function serve(
|
|
23
23
|
directory,
|
|
24
|
-
{ port = 4178, host = "127.0.0.1", viewer, packageRoot } = {},
|
|
24
|
+
{ port = 4178, host = "127.0.0.1", viewer, packageRoot, handler } = {},
|
|
25
25
|
) {
|
|
26
26
|
const root = await realpath(resolve(directory));
|
|
27
27
|
if (!(await stat(root)).isDirectory()) throw new Error("Serve root must be a directory.");
|
|
@@ -30,6 +30,7 @@ export async function serve(
|
|
|
30
30
|
res.writeHead(status, { "Content-Type": "text/plain; charset=utf-8" });
|
|
31
31
|
res.end(message);
|
|
32
32
|
};
|
|
33
|
+
if (handler && (await handler(req, res))) return;
|
|
33
34
|
if (!["GET", "HEAD"].includes(req.method)) return fail(405, "Method not allowed");
|
|
34
35
|
try {
|
|
35
36
|
const pathname = decodeURIComponent(new URL(req.url, "http://localhost").pathname);
|
package/bin/viewer.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { progressHandler } from "./progress.js";
|
|
1
3
|
import { readFile, realpath, stat } from "node:fs/promises";
|
|
2
4
|
import { resolve, dirname, relative, sep } from "node:path";
|
|
3
5
|
import { validateAtlas, AtlasValidationError } from "../src/config.js";
|
|
@@ -15,6 +17,12 @@ export async function serveAtlas(file, options = {}) {
|
|
|
15
17
|
if (rel === ".." || rel.startsWith(".." + sep) || rel.startsWith(sep))
|
|
16
18
|
throw new Error("The JSON file must be inside --root.");
|
|
17
19
|
const configURL = "/" + rel.split(sep).map(encodeURIComponent).join("/");
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
+
const token = randomBytes(24).toString("hex");
|
|
21
|
+
const html = `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>KetAtlas</title><style>html,body{margin:0;height:100%}#atlas{height:100dvh}#error{font:16px system-ui;padding:24px;white-space:pre-wrap}</style></head><body><main id="atlas"></main><pre id="error" hidden></pre><script type="module">import {loadAtlas} from '/__ketatlas__/src/index.js';try{window.atlas=await loadAtlas(document.querySelector('#atlas'),${JSON.stringify(configURL).replaceAll("<", "\\u003c")},{syncUrl:true,progressEndpoint:"/__ketatlas__/progress",progressToken:${JSON.stringify(token)}});document.title=${JSON.stringify(config.title).replaceAll("<", "\\u003c")}+' · KetAtlas';}catch(error){const el=document.querySelector('#error');el.hidden=false;el.textContent=error.message;}</script></body></html>`;
|
|
22
|
+
return serve(root, {
|
|
23
|
+
...options,
|
|
24
|
+
viewer: html,
|
|
25
|
+
packageRoot,
|
|
26
|
+
handler: progressHandler(absolute, absolute, token, !options.readOnly),
|
|
27
|
+
});
|
|
20
28
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Create mockups with an agent
|
|
2
|
+
|
|
3
|
+
Give an agent the KetAtlas skill and a product brief. The agent produces real HTML screens plus `atlas.json`; KetAtlas opens those files as an interactive workflow map. The brief describes the product, while the generated JSON schema and CLI audit check the output format.
|
|
4
|
+
|
|
5
|
+
## Install the skill once
|
|
6
|
+
|
|
7
|
+
From the project in which you want to create mockups:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npx skills add ketvietlab/ketatlas --skill ketatlas
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Choose your agent when prompted, or target it directly:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npx skills add ketvietlab/ketatlas --skill ketatlas --agent codex
|
|
17
|
+
npx skills add ketvietlab/ketatlas --skill ketatlas --agent claude-code
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
These commands use the separate [open agent skills CLI](https://github.com/vercel-labs/skills). Installation is project-scoped by default. The skill is a single portable [SKILL.md](../skills/ketatlas/SKILL.md), not a new KetAtlas command or a hosted generation service.
|
|
21
|
+
|
|
22
|
+
If the agent does not support skill installation, attach that file or ask it to read [the skill on GitHub](https://github.com/ketvietlab/ketatlas/blob/develop/skills/ketatlas/SKILL.md) before working. Installing a skill does not require changing the product repository's runtime dependencies.
|
|
23
|
+
|
|
24
|
+
## Ask for a mockup
|
|
25
|
+
|
|
26
|
+
For a short request, invoke the skill and include the product, target, design reference, and flows:
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
Use $ketatlas to create one shared HTML mobile prototype for Northstar Tasks
|
|
30
|
+
in ./tasks/mobile. Use 390 × 844 screens, English product copy, and the design
|
|
31
|
+
system in ./design-system. Include sign-in, password recovery, task list,
|
|
32
|
+
task details, and task completion. Map entry points, actions, outcomes, and
|
|
33
|
+
relevant error/recovery states. Implement the main interactions, then audit
|
|
34
|
+
and preview the result. Return the serve command and verification results.
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`$ketatlas` is the explicit skill invocation in Codex. In other agents, use that agent's skill selector or explicitly ask it to use the installed KetAtlas skill. Keep the same product brief.
|
|
38
|
+
|
|
39
|
+
The deliverable is data and product screen assets: JSON/schema, HTML/CSS/JavaScript, local assets, and documentation. Do not add a package manifest, lockfile, node_modules, or copied viewer/test tooling to make the atlas runnable. Use a global KetAtlas installation or a version-pinned npx command. Browser checks can use the agent's existing tooling outside the atlas folder.
|
|
40
|
+
|
|
41
|
+
The agent should infer routine details and record assumptions. Provide an exact list when “all screens” means a defined inventory, so missing coverage can be checked against a source.
|
|
42
|
+
|
|
43
|
+
## Use a saved brief for larger projects
|
|
44
|
+
|
|
45
|
+
Save this template as `mockup-brief.md`, fill in the relevant fields, and ask: **“Use the KetAtlas skill to implement mockup-brief.md.”** The brief stays Markdown; do not add its planning fields to `atlas.json`.
|
|
46
|
+
|
|
47
|
+
```markdown
|
|
48
|
+
# Mockup brief
|
|
49
|
+
|
|
50
|
+
- Product and audience:
|
|
51
|
+
- User goal:
|
|
52
|
+
- Output directory:
|
|
53
|
+
- Target platforms and viewport sizes:
|
|
54
|
+
- Product content language:
|
|
55
|
+
- Design system, existing HTML, and reference files/URLs:
|
|
56
|
+
- Requested flows and screen inventory:
|
|
57
|
+
- Relevant loading, empty, validation, error, and recovery states:
|
|
58
|
+
- Interactions to demonstrate and synthetic demo inputs:
|
|
59
|
+
- Scope exclusions and any intentional remote dependencies:
|
|
60
|
+
|
|
61
|
+
## Expected delivery
|
|
62
|
+
|
|
63
|
+
Create actual HTML screens and one KetAtlas version 1 atlas.json. Reuse
|
|
64
|
+
screens and styles across flows. Set explicit flow starts, outcomes, and
|
|
65
|
+
labelled transitions. Each named screen state must open directly.
|
|
66
|
+
|
|
67
|
+
Use the generated ketatlas.schema.json. Run KetAtlas audit, test the
|
|
68
|
+
important interactions in the viewer when browser automation is available,
|
|
69
|
+
and report results or limitations. Include a README with run commands,
|
|
70
|
+
flow coverage, demo inputs, and assumptions. Keep the output free of package
|
|
71
|
+
manifests, lockfiles, local dependencies, and copied viewer/test tooling.
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
For an existing prototype, ask the agent to reuse its HTML and add or update the atlas instead of rebuilding it. For later changes, name the flow or screen IDs to preserve, for example: **“Add an expired-code recovery branch to sign-in; keep existing screen IDs and audit the updated project.”**
|
|
75
|
+
|
|
76
|
+
## Review the result
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
npx ketatlas serve ./tasks/mobile/atlas.json
|
|
80
|
+
npx ketatlas audit ./tasks/mobile/atlas.json --strict
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Check the delivered flow coverage against the brief. Open **Try this screen** to test the actual HTML. A successful audit confirms structural and local-file checks, not visual quality, full product coverage, or working production integrations. Intentional remote URLs require separate verification and produce strict-audit warnings.
|
|
84
|
+
|
|
85
|
+
The skill lives in this repository so teams can review and evolve it alongside the schema and CLI. It works with the published `ketatlas@0.1.1` format; the skill itself can be distributed through GitHub without waiting for a new npm release.
|
package/docs/architecture.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Architecture
|
|
2
2
|
|
|
3
|
-
KetAtlas is a static browser viewer plus a Node.js command-line toolkit. There is no database, account service
|
|
3
|
+
KetAtlas is a static browser viewer plus a Node.js command-line toolkit. There is no database, account service or runtime npm dependency. The localhost CLI has a narrow, protected API to read and save the progress sidecar; static hosting remains read-only.
|
|
4
4
|
|
|
5
5
|
```text
|
|
6
6
|
atlas.json + screen HTML
|
|
@@ -15,6 +15,12 @@ atlas.json + screen HTML
|
|
|
15
15
|
└── lazy HTML iframes + interactive inspector
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
+
## Consumer boundary
|
|
19
|
+
|
|
20
|
+
KetAtlas is installed globally or executed through npx. Consumers provide JSON, a schema, HTML/CSS/JavaScript mock screens, assets, and documentation. They do not need a Node package, lockfile, development dependencies, viewer implementation, or build/test scripts to scaffold, serve, or audit a map.
|
|
21
|
+
|
|
22
|
+
The package owns the CLI, viewer, validation, and framework verification. A product may have its own application tests elsewhere; those are independent of the map format. Static audit does not simulate product interactions. Agent browser checks can run through external tooling without adding a test harness to the delivered atlas folder.
|
|
23
|
+
|
|
18
24
|
## Ownership
|
|
19
25
|
|
|
20
26
|
| Directory | Responsibility |
|
|
@@ -55,3 +61,7 @@ The default theme uses Inter and KetJS's canonical tokens and primitives. `prepa
|
|
|
55
61
|
## Version 1 boundaries
|
|
56
62
|
|
|
57
63
|
KetAtlas is a viewer and authoring toolkit, not a visual graph editor. Users edit JSON and HTML in their normal tools. It does not record a graph by watching clicks, synthesize screens, calculate backend permissions, or execute the arrow graph as an automated test. Cross-flow edges, collaborative editing and browser-based project audits are outside the current contract.
|
|
64
|
+
|
|
65
|
+
## Delivery tracking
|
|
66
|
+
|
|
67
|
+
`src/progress.js` owns progress validation and unique-screen counts. `src/progress-ui.js` owns the screen register and progress editor. `bin/progress.js` shares a locked, revision-checked atomic writer between CLI and local HTTP updates. Progress does not alter graph layout or infer completion from PR state. See [Screen progress](progress.md).
|
package/docs/cli.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# CLI reference
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Install once with `npm install --global ketatlas@0.1.1`, or prefix commands with `npx --yes ketatlas@0.1.1`. No dependency installation is required in the consumer directory. `node /path/to/ketatlas/bin/ketatlas.js` is also available to framework maintainers.
|
|
4
|
+
|
|
5
|
+
A consumer keeps only its JSON/schema, product HTML/CSS/JavaScript, assets, and documentation. The package manifest, lockfile, development scripts, and browser test dependencies belong to the tool. Normal `serve`, `validate`, and `audit` calls do not create files in the consumer; `audit --output` is an explicit exception.
|
|
4
6
|
|
|
5
7
|
## Scaffold
|
|
6
8
|
|
|
@@ -68,3 +70,7 @@ ketatlas --help
|
|
|
68
70
|
```
|
|
69
71
|
|
|
70
72
|
`validate` checks configuration and graph references only. It is also available as `validateAtlas(data)` in JavaScript. JSON Schema supports editor completion; graph-reference and URL safety checks belong to the runtime validator and audit.
|
|
73
|
+
|
|
74
|
+
## Screen progress
|
|
75
|
+
|
|
76
|
+
`progress <atlas.json> --json` reads the progress record, content revision and unique-screen summary. `--init` creates a missing sidecar. `--set <screen-id> --record <record.json> --expect <revision>` replaces one record with conflict detection. `serve <atlas.json> --read-only` disables local progress writes. See [Screen progress](progress.md) for examples and persistence rules.
|
package/docs/configuration.md
CHANGED
|
@@ -63,3 +63,7 @@ A node without `screen` defaults to `note` and requires a title. Use `type: "ext
|
|
|
63
63
|
`from`, `to` and a nonempty `label` are required. Endpoints reference node IDs in the same flow. `kind` is `primary` (default), `conditional`, or `recovery`. Arrows are orthogonal and labels describe the action or condition.
|
|
64
64
|
|
|
65
65
|
Cross-flow edges are not part of version 1. Reuse the destination screen in another flow, or add an external/note handoff to explain the boundary. Start and outcome markers express authored intent; clicking them does not invoke a backend operation.
|
|
66
|
+
|
|
67
|
+
## Delivery progress
|
|
68
|
+
|
|
69
|
+
Delivery records use the optional sibling `<atlas-name>.progress.json`, with `progress.schema.json` and semantic validation, rather than extra properties in the version 1 workflow. See [Screen progress](progress.md).
|
package/docs/integration.md
CHANGED
|
@@ -106,3 +106,7 @@ Iframe previews are sandboxed. Scripts and forms work by default, but the page h
|
|
|
106
106
|
Remote pages can reject framing using CSP or `X-Frame-Options`. KetAtlas cannot override that. Use a permitted embedded route or the **Open in new tab** action. Test links/forms with the default sandbox before sharing a project.
|
|
107
107
|
|
|
108
108
|
The viewer uses native dialog, Shadow DOM, ResizeObserver, container queries and modern CSS. Chromium is covered by the browser suite. Other modern engines should be qualified against your host application before promising support.
|
|
109
|
+
|
|
110
|
+
## Progress adapters
|
|
111
|
+
|
|
112
|
+
`createAtlas` accepts `options.progress`. `loadAtlas` discovers a sibling progress JSON or accepts `progressURL`. Both support `progressRevision`, `saveProgress(screenId, record, revision)` and `reloadProgress()`; adapters return `{data, revision}`. No save adapter means read-only. See [Screen progress](progress.md).
|
package/docs/migration.md
CHANGED
|
@@ -30,6 +30,7 @@ Keep the existing screen IDs. Give repeated states unique node IDs, but reuse th
|
|
|
30
30
|
3. Set the default viewport to 390 × 844. Keep DOC/TARGET source labels if useful to reviewers.
|
|
31
31
|
4. Run `ketatlas audit atlas.json --root <project-root>` and resolve diagnostics.
|
|
32
32
|
5. Run `ketatlas serve atlas.json --root <project-root>` and compare the existing 22 journeys, 108 screen IDs, and 162 edges against the exported graph.
|
|
33
|
-
6.
|
|
33
|
+
6. Recheck product interactions with external browser tooling under the default iframe sandbox; use portable HTML rather than weakening the sandbox.
|
|
34
|
+
7. Remove the old viewer tooling, package manifest, lockfile, and local build/test dependencies from the atlas folder. Keep screen HTML/CSS/JavaScript and its assets. Use global or version-pinned npx commands for serving and auditing. Record any earlier browser reports as historical evidence rather than requiring the old harness to run the map.
|
|
34
35
|
|
|
35
36
|
KetAtlas UI is English. Vietnamese business labels inside the project's configuration and HTML can remain Vietnamese.
|