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 CHANGED
@@ -1,6 +1,22 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.0 — Initial scaffold
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
- This entry describes the source version; it does not confirm publication to npm.
29
+ Published to [npm](https://www.npmjs.com/package/ketatlas/v/0.1.0).
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 KETVIET JSC, Vietnam
3
+ Copyright (c) 2026 KET VIET JSC, VN
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/NOTICE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Third-party notices
2
2
 
3
- KetAtlas is maintained by KETVIET JSC under the MIT license.
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
- ## Start from this repository
9
+ ## Demo
10
10
 
11
- ```sh
12
- git clone git@github.com:ketvietlab/ketatlas.git
13
- cd ketatlas
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
- Open **http://127.0.0.1:4178**. The playground includes mobile sign-in, a desktop approval flow, and a fulfilment process.
15
+ ## Run without a project install
19
16
 
20
- Create your own project:
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
- node bin/ketatlas.js scaffold ../my-atlas
24
- node bin/ketatlas.js serve ../my-atlas/atlas.json
25
- node bin/ketatlas.js audit ../my-atlas/atlas.json --strict
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
- No wrapper HTML is needed. Edit `atlas.json` and the files under `screens/`, then refresh the browser.
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
- npx --yes --package ~/dev/ketatlas ketatlas scaffold my-atlas
36
- npx --yes --package ~/dev/ketatlas ketatlas serve my-atlas/atlas.json
37
- npx --yes --package ~/dev/ketatlas ketatlas audit my-atlas/atlas.json --strict
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
- Replace `~/dev/ketatlas` with your checkout path. This uses the local package, not an npm registry release.
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
- Once the source has been pushed to GitHub, run without cloning it yourself:
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
- ```sh
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
- After `ketatlas` has been published to npm, the short form is:
40
+ ## Create mockups with an agent
41
+
42
+ Install the KetAtlas skill in your product project:
51
43
 
52
44
  ```sh
53
- npx ketatlas scaffold my-atlas --template web
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
- The repository does not imply an npm release. Package installation is tested from the actual `.tgz` archive; release instructions are in [Releasing](docs/releasing.md).
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
- MIT · [Third-party notices](NOTICE.md).
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, { port: "string", root: "string" }),
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
  );
@@ -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 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});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>`;
19
- return serve(root, { ...options, viewer: html, packageRoot });
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.
@@ -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, application backend, or runtime npm dependency.
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
- Use `ketatlas` after installing the package, `node /path/to/ketatlas/bin/ketatlas.js` from a checkout, or the npx forms in the [README](../README.md).
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.
@@ -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).
@@ -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. Re-run the project's browser interactions under the iframe sandbox. Only enable additional sandbox permissions for trusted HTML when its behavior requires them.
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.