@cr8rcho/alkahest 0.1.1
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/README.ko.md +208 -0
- package/README.md +208 -0
- package/dist/assets/dashboard.html +647 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +68 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/hook.d.ts +1 -0
- package/dist/commands/hook.js +64 -0
- package/dist/commands/hook.js.map +1 -0
- package/dist/commands/login.d.ts +11 -0
- package/dist/commands/login.js +27 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/mcp.d.ts +6 -0
- package/dist/commands/mcp.js +13 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/publish.d.ts +19 -0
- package/dist/commands/publish.js +27 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/scan.d.ts +11 -0
- package/dist/commands/scan.js +29 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/update.d.ts +15 -0
- package/dist/commands/update.js +41 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/view.d.ts +6 -0
- package/dist/commands/view.js +21 -0
- package/dist/commands/view.js.map +1 -0
- package/dist/core/adapters/angular.d.ts +2 -0
- package/dist/core/adapters/angular.js +305 -0
- package/dist/core/adapters/angular.js.map +1 -0
- package/dist/core/adapters/astro.d.ts +3 -0
- package/dist/core/adapters/astro.js +140 -0
- package/dist/core/adapters/astro.js.map +1 -0
- package/dist/core/adapters/compose.d.ts +2 -0
- package/dist/core/adapters/compose.js +195 -0
- package/dist/core/adapters/compose.js.map +1 -0
- package/dist/core/adapters/django.d.ts +2 -0
- package/dist/core/adapters/django.js +314 -0
- package/dist/core/adapters/django.js.map +1 -0
- package/dist/core/adapters/expo-router.d.ts +2 -0
- package/dist/core/adapters/expo-router.js +60 -0
- package/dist/core/adapters/expo-router.js.map +1 -0
- package/dist/core/adapters/flask.d.ts +2 -0
- package/dist/core/adapters/flask.js +249 -0
- package/dist/core/adapters/flask.js.map +1 -0
- package/dist/core/adapters/flutter.d.ts +2 -0
- package/dist/core/adapters/flutter.js +232 -0
- package/dist/core/adapters/flutter.js.map +1 -0
- package/dist/core/adapters/index.d.ts +19 -0
- package/dist/core/adapters/index.js +59 -0
- package/dist/core/adapters/index.js.map +1 -0
- package/dist/core/adapters/next-app.d.ts +2 -0
- package/dist/core/adapters/next-app.js +62 -0
- package/dist/core/adapters/next-app.js.map +1 -0
- package/dist/core/adapters/next-pages.d.ts +2 -0
- package/dist/core/adapters/next-pages.js +70 -0
- package/dist/core/adapters/next-pages.js.map +1 -0
- package/dist/core/adapters/nuxt.d.ts +2 -0
- package/dist/core/adapters/nuxt.js +59 -0
- package/dist/core/adapters/nuxt.js.map +1 -0
- package/dist/core/adapters/rails.d.ts +2 -0
- package/dist/core/adapters/rails.js +275 -0
- package/dist/core/adapters/rails.js.map +1 -0
- package/dist/core/adapters/react-jsx.d.ts +68 -0
- package/dist/core/adapters/react-jsx.js +355 -0
- package/dist/core/adapters/react-jsx.js.map +1 -0
- package/dist/core/adapters/react-navigation.d.ts +2 -0
- package/dist/core/adapters/react-navigation.js +153 -0
- package/dist/core/adapters/react-navigation.js.map +1 -0
- package/dist/core/adapters/react-router.d.ts +2 -0
- package/dist/core/adapters/react-router.js +249 -0
- package/dist/core/adapters/react-router.js.map +1 -0
- package/dist/core/adapters/remix.d.ts +2 -0
- package/dist/core/adapters/remix.js +109 -0
- package/dist/core/adapters/remix.js.map +1 -0
- package/dist/core/adapters/static-html.d.ts +2 -0
- package/dist/core/adapters/static-html.js +157 -0
- package/dist/core/adapters/static-html.js.map +1 -0
- package/dist/core/adapters/sveltekit.d.ts +2 -0
- package/dist/core/adapters/sveltekit.js +151 -0
- package/dist/core/adapters/sveltekit.js.map +1 -0
- package/dist/core/adapters/swiftui.d.ts +2 -0
- package/dist/core/adapters/swiftui.js +216 -0
- package/dist/core/adapters/swiftui.js.map +1 -0
- package/dist/core/adapters/types.d.ts +65 -0
- package/dist/core/adapters/types.js +2 -0
- package/dist/core/adapters/types.js.map +1 -0
- package/dist/core/adapters/uikit.d.ts +2 -0
- package/dist/core/adapters/uikit.js +178 -0
- package/dist/core/adapters/uikit.js.map +1 -0
- package/dist/core/adapters/vue-router.d.ts +2 -0
- package/dist/core/adapters/vue-router.js +224 -0
- package/dist/core/adapters/vue-router.js.map +1 -0
- package/dist/core/adapters/vue-sfc.d.ts +28 -0
- package/dist/core/adapters/vue-sfc.js +132 -0
- package/dist/core/adapters/vue-sfc.js.map +1 -0
- package/dist/core/credentials.d.ts +24 -0
- package/dist/core/credentials.js +30 -0
- package/dist/core/credentials.js.map +1 -0
- package/dist/core/dashboard.d.ts +9 -0
- package/dist/core/dashboard.js +20 -0
- package/dist/core/dashboard.js.map +1 -0
- package/dist/core/emit.d.ts +7 -0
- package/dist/core/emit.js +23 -0
- package/dist/core/emit.js.map +1 -0
- package/dist/core/hash.d.ts +2 -0
- package/dist/core/hash.js +6 -0
- package/dist/core/hash.js.map +1 -0
- package/dist/core/pipeline.d.ts +25 -0
- package/dist/core/pipeline.js +122 -0
- package/dist/core/pipeline.js.map +1 -0
- package/dist/core/publish.d.ts +31 -0
- package/dist/core/publish.js +87 -0
- package/dist/core/publish.js.map +1 -0
- package/dist/core/resolve.d.ts +42 -0
- package/dist/core/resolve.js +128 -0
- package/dist/core/resolve.js.map +1 -0
- package/dist/core/serve.d.ts +5 -0
- package/dist/core/serve.js +52 -0
- package/dist/core/serve.js.map +1 -0
- package/dist/core/types.d.ts +117 -0
- package/dist/core/types.js +9 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/version.d.ts +23 -0
- package/dist/core/version.js +102 -0
- package/dist/core/version.js.map +1 -0
- package/dist/mcp/server.d.ts +7 -0
- package/dist/mcp/server.js +224 -0
- package/dist/mcp/server.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { selectAdapter } from "./adapters/index.js";
|
|
5
|
+
import { buildMap, screenFromRaw, resolveTransitions, resolveContains, resolveCalls, assembleMap, isExternalUrl, } from "./resolve.js";
|
|
6
|
+
import { emitMap, emitDashboard, OUTPUT_DIR } from "./emit.js";
|
|
7
|
+
import { hashContent } from "./hash.js";
|
|
8
|
+
const require = createRequire(import.meta.url);
|
|
9
|
+
const pkg = require("../../package.json");
|
|
10
|
+
/**
|
|
11
|
+
* Core pipeline detect→discover→parse→resolve→emit (no console output).
|
|
12
|
+
* Framework is auto-selected via adapters (ALKAHEST.md §8). Incremental by default (§10).
|
|
13
|
+
* Null if no screens are found. Shared by the CLI (scan) and the MCP server.
|
|
14
|
+
*/
|
|
15
|
+
export function runScan(projectRoot, options = {}) {
|
|
16
|
+
const adapter = selectAdapter(projectRoot);
|
|
17
|
+
if (!adapter)
|
|
18
|
+
return null;
|
|
19
|
+
const files = adapter.discover(projectRoot);
|
|
20
|
+
if (!files.length)
|
|
21
|
+
return null;
|
|
22
|
+
const hashes = new Map();
|
|
23
|
+
for (const file of files)
|
|
24
|
+
hashes.set(file.relPath, hashContent(readFileSync(file.absPath, "utf8")));
|
|
25
|
+
const prev = options.full ? null : loadMap(projectRoot);
|
|
26
|
+
const result = prev
|
|
27
|
+
? incrementalBuild(adapter, files, hashes, prev, projectRoot)
|
|
28
|
+
: fullBuild(adapter, files, hashes, projectRoot);
|
|
29
|
+
const outFile = emitMap(projectRoot, result.map);
|
|
30
|
+
emitDashboard(projectRoot, result.map);
|
|
31
|
+
return { ...result, outFile };
|
|
32
|
+
}
|
|
33
|
+
function fullBuild(adapter, files, hashes, projectRoot) {
|
|
34
|
+
const parsed = new Map();
|
|
35
|
+
for (const file of files)
|
|
36
|
+
parsed.set(file.relPath, adapter.parse(file));
|
|
37
|
+
const map = buildMap({
|
|
38
|
+
files,
|
|
39
|
+
parsed,
|
|
40
|
+
hashes,
|
|
41
|
+
framework: adapter.id,
|
|
42
|
+
router: adapter.router,
|
|
43
|
+
projectRoot,
|
|
44
|
+
scannedAt: new Date().toISOString(),
|
|
45
|
+
alkahestVersion: pkg.version,
|
|
46
|
+
});
|
|
47
|
+
return { map, stats: { reused: 0, reparsed: map.screens.length, total: map.screens.length, incremental: false } };
|
|
48
|
+
}
|
|
49
|
+
function incrementalBuild(adapter, files, hashes, prev, projectRoot) {
|
|
50
|
+
const screenIds = new Set(files.map((f) => f.id));
|
|
51
|
+
const prevScreenByFile = new Map(prev.screens.map((s) => [s.sourceFile, s]));
|
|
52
|
+
const prevResById = new Map(prev.resources.map((r) => [r.id, r]));
|
|
53
|
+
const screens = [];
|
|
54
|
+
const transitions = [];
|
|
55
|
+
const calls = [];
|
|
56
|
+
const resources = new Map();
|
|
57
|
+
let reused = 0;
|
|
58
|
+
let reparsed = 0;
|
|
59
|
+
for (const file of files) {
|
|
60
|
+
const prevScreen = prevScreenByFile.get(file.relPath);
|
|
61
|
+
const unchanged = prevScreen && prev.meta.fileHashes[file.relPath] === hashes.get(file.relPath);
|
|
62
|
+
if (unchanged) {
|
|
63
|
+
reused++;
|
|
64
|
+
screens.push(prevScreen); // preserve as-is, including summary
|
|
65
|
+
transitions.push(...prev.transitions.filter((t) => t.loc.file === file.relPath));
|
|
66
|
+
for (const c of prev.calls.filter((c) => c.loc.file === file.relPath)) {
|
|
67
|
+
calls.push(c);
|
|
68
|
+
if (c.to) {
|
|
69
|
+
const r = prevResById.get(c.to);
|
|
70
|
+
if (r && !resources.has(r.id))
|
|
71
|
+
resources.set(r.id, r);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
reparsed++;
|
|
77
|
+
const raw = adapter.parse(file);
|
|
78
|
+
screens.push(screenFromRaw(file, hashes.get(file.relPath) ?? "", raw));
|
|
79
|
+
const navTrans = resolveTransitions(file.id, raw.navs, screenIds, file.relPath);
|
|
80
|
+
transitions.push(...navTrans);
|
|
81
|
+
transitions.push(...resolveContains(file.id, raw.contains, screenIds, navTrans, file.relPath));
|
|
82
|
+
calls.push(...resolveCalls(file.id, raw.calls, file.relPath, resources));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Re-resolve reused edges against the new screen set: internal transitions pointing to a vanished screen become unresolved.
|
|
86
|
+
for (const t of transitions) {
|
|
87
|
+
if (t.to && !isExternalUrl(t.to) && !screenIds.has(t.to)) {
|
|
88
|
+
t.rawTarget = t.rawTarget ?? t.to;
|
|
89
|
+
t.to = null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const map = assembleMap({
|
|
93
|
+
screens,
|
|
94
|
+
transitions,
|
|
95
|
+
calls,
|
|
96
|
+
resources: [...resources.values()],
|
|
97
|
+
hashes,
|
|
98
|
+
framework: adapter.id,
|
|
99
|
+
router: adapter.router,
|
|
100
|
+
projectRoot,
|
|
101
|
+
scannedAt: new Date().toISOString(),
|
|
102
|
+
alkahestVersion: pkg.version,
|
|
103
|
+
});
|
|
104
|
+
return { map, stats: { reused, reparsed, total: screens.length, incremental: true } };
|
|
105
|
+
}
|
|
106
|
+
/** Reads an existing `.alkahest/map.json` (null if absent). */
|
|
107
|
+
export function loadMap(projectRoot) {
|
|
108
|
+
const file = join(projectRoot, OUTPUT_DIR, "map.json");
|
|
109
|
+
if (!existsSync(file))
|
|
110
|
+
return null;
|
|
111
|
+
try {
|
|
112
|
+
return JSON.parse(readFileSync(file, "utf8"));
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/** Reads map.json if present, otherwise scans on the fly. Null if both fail. */
|
|
119
|
+
export function loadOrScan(projectRoot) {
|
|
120
|
+
return loadMap(projectRoot) ?? runScan(projectRoot)?.map ?? null;
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=pipeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/core/pipeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared publish logic used by both the `alkahest publish` CLI command and the MCP
|
|
3
|
+
* `publish` tool. Uploads `<projectRoot>/.alkahest/map.json` to the hosted viewer.
|
|
4
|
+
* Only map.json is sent; source code never leaves the machine.
|
|
5
|
+
*
|
|
6
|
+
* This returns a structured result and never writes to stdout/stderr — the MCP server
|
|
7
|
+
* reserves stdout for JSON-RPC, so callers (CLI) own all user-facing output.
|
|
8
|
+
*/
|
|
9
|
+
export interface PublishParams {
|
|
10
|
+
/** API base URL (else env ALKAHEST_API_URL / saved creds). */
|
|
11
|
+
api?: string;
|
|
12
|
+
/** Project name shown in the URL/dashboard (first publish only; defaults to folder name). */
|
|
13
|
+
name?: string;
|
|
14
|
+
/** Publish token (else env ALKAHEST_TOKEN / saved creds). */
|
|
15
|
+
token?: string;
|
|
16
|
+
/** Which surface initiated this — sent to the server for version/compat handling. */
|
|
17
|
+
source?: "cli" | "mcp";
|
|
18
|
+
}
|
|
19
|
+
export interface PublishResult {
|
|
20
|
+
ok: boolean;
|
|
21
|
+
slug?: string;
|
|
22
|
+
viewerUrl?: string | null;
|
|
23
|
+
mapUrl?: string;
|
|
24
|
+
/** Whether this was the project's first publish (a new slug was created). */
|
|
25
|
+
created?: boolean;
|
|
26
|
+
/** Machine-readable failure code: no_map | no_api | no_token | network | <server error>. */
|
|
27
|
+
code?: string;
|
|
28
|
+
/** Human-readable failure message. */
|
|
29
|
+
message?: string;
|
|
30
|
+
}
|
|
31
|
+
export declare function publishMap(path: string, params?: PublishParams): Promise<PublishResult>;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { basename, join, resolve } from "node:path";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { OUTPUT_DIR } from "./emit.js";
|
|
5
|
+
import { loadCredentials, resolveApiUrl, resolveToken, saveCredentials } from "./credentials.js";
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
7
|
+
const pkg = require("../../package.json");
|
|
8
|
+
async function postJson(url, body, token) {
|
|
9
|
+
let res;
|
|
10
|
+
try {
|
|
11
|
+
res = await fetch(url, {
|
|
12
|
+
method: "POST",
|
|
13
|
+
headers: { "content-type": "application/json", authorization: `Bearer ${token}` },
|
|
14
|
+
body: JSON.stringify(body),
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
19
|
+
return { ok: false, status: "network", body: { error: `could not reach ${url} (${msg})` } };
|
|
20
|
+
}
|
|
21
|
+
let parsed = null;
|
|
22
|
+
try {
|
|
23
|
+
parsed = await res.json();
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
/* non-JSON error body */
|
|
27
|
+
}
|
|
28
|
+
return { ok: res.ok, status: String(res.status), body: parsed };
|
|
29
|
+
}
|
|
30
|
+
export async function publishMap(path, params = {}) {
|
|
31
|
+
const projectRoot = resolve(path);
|
|
32
|
+
const mapFile = join(projectRoot, OUTPUT_DIR, "map.json");
|
|
33
|
+
if (!existsSync(mapFile)) {
|
|
34
|
+
return { ok: false, code: "no_map", message: `No ${OUTPUT_DIR}/map.json found — run scan first.` };
|
|
35
|
+
}
|
|
36
|
+
const map = JSON.parse(readFileSync(mapFile, "utf8"));
|
|
37
|
+
const creds = loadCredentials();
|
|
38
|
+
const apiUrl = resolveApiUrl(params.api, creds);
|
|
39
|
+
if (!apiUrl) {
|
|
40
|
+
return {
|
|
41
|
+
ok: false,
|
|
42
|
+
code: "no_api",
|
|
43
|
+
message: "Missing API URL. Set ALKAHEST_API_URL (or pass --api / run 'alkahest login --api <url>').",
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const token = resolveToken(params.token, creds);
|
|
47
|
+
if (!token) {
|
|
48
|
+
return {
|
|
49
|
+
ok: false,
|
|
50
|
+
code: "no_token",
|
|
51
|
+
message: "Not authenticated. Set ALKAHEST_TOKEN (or run 'alkahest login --token alk_…').",
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
// Known project → send its slug (update). New project → omit slug (server creates it).
|
|
55
|
+
const known = creds.projects?.[projectRoot];
|
|
56
|
+
const reqBody = {
|
|
57
|
+
map,
|
|
58
|
+
client: { source: params.source ?? "cli", version: pkg.version },
|
|
59
|
+
};
|
|
60
|
+
if (known)
|
|
61
|
+
reqBody.slug = known.slug;
|
|
62
|
+
else
|
|
63
|
+
reqBody.name = params.name || basename(projectRoot);
|
|
64
|
+
const pub = await postJson(`${apiUrl}/publish`, reqBody, token);
|
|
65
|
+
if (!pub.ok) {
|
|
66
|
+
return {
|
|
67
|
+
ok: false,
|
|
68
|
+
code: pub.body?.error ?? "http",
|
|
69
|
+
message: pub.body?.message ?? pub.body?.error ?? `publish failed (${pub.status})`,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
// Remember the slug for this project path so future publishes update the same link.
|
|
73
|
+
const created = !known && Boolean(pub.body.slug);
|
|
74
|
+
if (created) {
|
|
75
|
+
creds.projects = creds.projects ?? {};
|
|
76
|
+
creds.projects[projectRoot] = { slug: pub.body.slug };
|
|
77
|
+
saveCredentials(creds);
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
ok: true,
|
|
81
|
+
slug: pub.body.slug,
|
|
82
|
+
viewerUrl: pub.body.viewerUrl ?? null,
|
|
83
|
+
mapUrl: pub.body.mapUrl,
|
|
84
|
+
created,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=publish.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/core/publish.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ProductMap, Screen, Resource, Transition, Call, Framework, Router } from "./types.js";
|
|
2
|
+
import type { ScreenFile, RawScreen, RawNav, RawCall } from "./adapters/types.js";
|
|
3
|
+
export interface ResolveInput {
|
|
4
|
+
files: ScreenFile[];
|
|
5
|
+
/** key = ScreenFile.relPath */
|
|
6
|
+
parsed: Map<string, RawScreen>;
|
|
7
|
+
/** key = ScreenFile.relPath → content hash */
|
|
8
|
+
hashes: Map<string, string>;
|
|
9
|
+
framework: Framework;
|
|
10
|
+
router: Router;
|
|
11
|
+
projectRoot: string;
|
|
12
|
+
scannedAt: string;
|
|
13
|
+
alkahestVersion: string;
|
|
14
|
+
}
|
|
15
|
+
/** Raw signals (parse) → 2-layer ProductMap (full build, ALKAHEST.md §3). Adapter-agnostic. */
|
|
16
|
+
export declare function buildMap(input: ResolveInput): ProductMap;
|
|
17
|
+
/** One screen file's raw signals → Screen node (excluding edges). title/id use the values the adapter assigned. */
|
|
18
|
+
export declare function screenFromRaw(file: ScreenFile, hash: string, raw: RawScreen): Screen;
|
|
19
|
+
/** A screen's navs → Transition[] (resolved against the set of screen ids). */
|
|
20
|
+
export declare function resolveTransitions(from: string, navs: RawNav[], screenIds: Set<string>, file: string): Transition[];
|
|
21
|
+
/**
|
|
22
|
+
* Child screens a screen instantiates → "contains" edges (structural flow, for identifying the start point).
|
|
23
|
+
* Only contains candidates that are real screens (screenIds); excludes itself and any already linked via nav.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveContains(from: string, candidates: string[], screenIds: Set<string>, existingNav: Transition[], file: string): Transition[];
|
|
26
|
+
/** A screen's calls → Call[]. Loads discovered Resources into resourceMap, deduplicated. */
|
|
27
|
+
export declare function resolveCalls(from: string, raw: RawCall[], file: string, resourceMap: Map<string, Resource>): Call[];
|
|
28
|
+
export declare function isExternalUrl(s: string): boolean;
|
|
29
|
+
export interface AssembleInput {
|
|
30
|
+
screens: Screen[];
|
|
31
|
+
transitions: Transition[];
|
|
32
|
+
calls: Call[];
|
|
33
|
+
resources: Resource[];
|
|
34
|
+
hashes: Map<string, string>;
|
|
35
|
+
framework: Framework;
|
|
36
|
+
router: Router;
|
|
37
|
+
projectRoot: string;
|
|
38
|
+
scannedAt: string;
|
|
39
|
+
alkahestVersion: string;
|
|
40
|
+
}
|
|
41
|
+
/** Nodes/edges/resources → final ProductMap (fills meta, sorts resources). */
|
|
42
|
+
export declare function assembleMap(a: AssembleInput): ProductMap;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/** Raw signals (parse) → 2-layer ProductMap (full build, ALKAHEST.md §3). Adapter-agnostic. */
|
|
2
|
+
export function buildMap(input) {
|
|
3
|
+
const { files, parsed, hashes } = input;
|
|
4
|
+
const screenIds = new Set(files.map((f) => f.id));
|
|
5
|
+
const screens = [];
|
|
6
|
+
const transitions = [];
|
|
7
|
+
const calls = [];
|
|
8
|
+
const resources = new Map();
|
|
9
|
+
for (const file of files) {
|
|
10
|
+
const raw = parsed.get(file.relPath);
|
|
11
|
+
if (!raw)
|
|
12
|
+
continue;
|
|
13
|
+
screens.push(screenFromRaw(file, hashes.get(file.relPath) ?? "", raw));
|
|
14
|
+
const navTrans = resolveTransitions(file.id, raw.navs, screenIds, file.relPath);
|
|
15
|
+
transitions.push(...navTrans);
|
|
16
|
+
// contains: other screens this screen directly instantiates → structural flow (entry point→tabs, etc.). §11
|
|
17
|
+
transitions.push(...resolveContains(file.id, raw.contains, screenIds, navTrans, file.relPath));
|
|
18
|
+
calls.push(...resolveCalls(file.id, raw.calls, file.relPath, resources));
|
|
19
|
+
}
|
|
20
|
+
return assembleMap({
|
|
21
|
+
screens,
|
|
22
|
+
transitions,
|
|
23
|
+
calls,
|
|
24
|
+
resources: [...resources.values()],
|
|
25
|
+
hashes,
|
|
26
|
+
framework: input.framework,
|
|
27
|
+
router: input.router,
|
|
28
|
+
projectRoot: input.projectRoot,
|
|
29
|
+
scannedAt: input.scannedAt,
|
|
30
|
+
alkahestVersion: input.alkahestVersion,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/** One screen file's raw signals → Screen node (excluding edges). title/id use the values the adapter assigned. */
|
|
34
|
+
export function screenFromRaw(file, hash, raw) {
|
|
35
|
+
return {
|
|
36
|
+
id: file.id,
|
|
37
|
+
route: file.route,
|
|
38
|
+
sourceFile: file.relPath,
|
|
39
|
+
sourceHash: hash,
|
|
40
|
+
title: file.title,
|
|
41
|
+
summary: "",
|
|
42
|
+
features: raw.features.map((f) => ({ kind: f.kind, label: f.label, detail: f.detail, loc: { file: file.relPath, line: f.line } })),
|
|
43
|
+
components: raw.components,
|
|
44
|
+
isEntry: file.isEntry,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** A screen's navs → Transition[] (resolved against the set of screen ids). */
|
|
48
|
+
export function resolveTransitions(from, navs, screenIds, file) {
|
|
49
|
+
return navs.map((nav) => resolveTransition(from, nav, screenIds, file));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Child screens a screen instantiates → "contains" edges (structural flow, for identifying the start point).
|
|
53
|
+
* Only contains candidates that are real screens (screenIds); excludes itself and any already linked via nav.
|
|
54
|
+
*/
|
|
55
|
+
export function resolveContains(from, candidates, screenIds, existingNav, file) {
|
|
56
|
+
const navTargets = new Set(existingNav.map((t) => t.to).filter(Boolean));
|
|
57
|
+
const out = [];
|
|
58
|
+
const seen = new Set();
|
|
59
|
+
for (const c of candidates) {
|
|
60
|
+
if (c === from || !screenIds.has(c) || navTargets.has(c) || seen.has(c))
|
|
61
|
+
continue;
|
|
62
|
+
seen.add(c);
|
|
63
|
+
out.push({ from, to: c, kind: "contains", trigger: "embed", loc: { file, line: 0 } });
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
/** A screen's calls → Call[]. Loads discovered Resources into resourceMap, deduplicated. */
|
|
68
|
+
export function resolveCalls(from, raw, file, resourceMap) {
|
|
69
|
+
return raw.map((call) => resolveCall(from, call, resourceMap, file));
|
|
70
|
+
}
|
|
71
|
+
export function isExternalUrl(s) {
|
|
72
|
+
return /^https?:\/\//.test(s);
|
|
73
|
+
}
|
|
74
|
+
/** Nodes/edges/resources → final ProductMap (fills meta, sorts resources). */
|
|
75
|
+
export function assembleMap(a) {
|
|
76
|
+
return {
|
|
77
|
+
screens: a.screens,
|
|
78
|
+
resources: a.resources.sort((x, y) => x.id.localeCompare(y.id)),
|
|
79
|
+
transitions: a.transitions,
|
|
80
|
+
calls: a.calls,
|
|
81
|
+
meta: {
|
|
82
|
+
framework: a.framework,
|
|
83
|
+
router: a.router,
|
|
84
|
+
scannedAt: a.scannedAt,
|
|
85
|
+
projectRoot: a.projectRoot,
|
|
86
|
+
fileHashes: Object.fromEntries(a.hashes),
|
|
87
|
+
alkahestVersion: a.alkahestVersion,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
// ---------- internals ----------
|
|
92
|
+
function resolveTransition(from, nav, screenIds, file) {
|
|
93
|
+
const loc = { file, line: nav.line };
|
|
94
|
+
const base = { from, kind: "navigate", trigger: nav.trigger, loc };
|
|
95
|
+
if (nav.target == null) {
|
|
96
|
+
return { ...base, to: null, rawTarget: nav.raw };
|
|
97
|
+
}
|
|
98
|
+
if (isExternalUrl(nav.target)) {
|
|
99
|
+
return { ...base, to: nav.target.split(/[?#]/)[0] };
|
|
100
|
+
}
|
|
101
|
+
const candidates = [nav.target, normalizeRoute(nav.target)];
|
|
102
|
+
const hit = candidates.find((c) => screenIds.has(c));
|
|
103
|
+
if (hit)
|
|
104
|
+
return { ...base, to: hit };
|
|
105
|
+
return { ...base, to: null, rawTarget: nav.target };
|
|
106
|
+
}
|
|
107
|
+
function normalizeRoute(target) {
|
|
108
|
+
const clean = target.split(/[?#]/)[0];
|
|
109
|
+
let route = clean.startsWith("/") ? clean : "/" + clean;
|
|
110
|
+
if (route.length > 1)
|
|
111
|
+
route = route.replace(/\/+$/, "");
|
|
112
|
+
return route;
|
|
113
|
+
}
|
|
114
|
+
function resolveCall(from, call, resources, file) {
|
|
115
|
+
const loc = { file, line: call.line };
|
|
116
|
+
if (call.url == null) {
|
|
117
|
+
return { from, to: null, rawTarget: call.raw, trigger: call.trigger, loc };
|
|
118
|
+
}
|
|
119
|
+
const path = call.url.split("#")[0];
|
|
120
|
+
const external = isExternalUrl(path);
|
|
121
|
+
const method = (call.method ?? "GET").toUpperCase();
|
|
122
|
+
const id = `${method} ${path}`;
|
|
123
|
+
if (!resources.has(id)) {
|
|
124
|
+
resources.set(id, { id, kind: external ? "external" : "endpoint", label: id, method, path });
|
|
125
|
+
}
|
|
126
|
+
return { from, to: id, trigger: call.trigger, loc };
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/core/resolve.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { extname, resolve } from "node:path";
|
|
4
|
+
import { spawn } from "node:child_process";
|
|
5
|
+
import { platform } from "node:os";
|
|
6
|
+
import { OUTPUT_DIR } from "./emit.js";
|
|
7
|
+
const MIME = {
|
|
8
|
+
".html": "text/html; charset=utf-8",
|
|
9
|
+
".json": "application/json; charset=utf-8",
|
|
10
|
+
".js": "text/javascript; charset=utf-8",
|
|
11
|
+
".css": "text/css; charset=utf-8",
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Serves `<projectRoot>/.alkahest` as a local static server and opens the browser.
|
|
15
|
+
* The server keeps the event loop alive, so the process stays up until Ctrl+C.
|
|
16
|
+
*/
|
|
17
|
+
export async function serveDashboard(projectRoot) {
|
|
18
|
+
const root = resolve(projectRoot, OUTPUT_DIR);
|
|
19
|
+
const server = createServer(async (req, res) => {
|
|
20
|
+
try {
|
|
21
|
+
const urlPath = decodeURIComponent((req.url || "/").split("?")[0]);
|
|
22
|
+
const filePath = resolve(root, "." + (urlPath === "/" ? "/index.html" : urlPath));
|
|
23
|
+
if (filePath !== root && !filePath.startsWith(root + "/")) {
|
|
24
|
+
res.writeHead(403).end("Forbidden");
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const data = await readFile(filePath);
|
|
28
|
+
res.writeHead(200, { "content-type": MIME[extname(filePath)] ?? "application/octet-stream" });
|
|
29
|
+
res.end(data);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
res.writeHead(404).end("Not found");
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
await new Promise((res) => server.listen(0, "127.0.0.1", res));
|
|
36
|
+
const addr = server.address();
|
|
37
|
+
const port = typeof addr === "object" && addr ? addr.port : 0;
|
|
38
|
+
const url = `http://127.0.0.1:${port}/`;
|
|
39
|
+
console.log(`[alkahest] dashboard: ${url} (Ctrl+C to stop)`);
|
|
40
|
+
openBrowser(url);
|
|
41
|
+
}
|
|
42
|
+
function openBrowser(url) {
|
|
43
|
+
const isWin = platform() === "win32";
|
|
44
|
+
const cmd = platform() === "darwin" ? "open" : isWin ? "start" : "xdg-open";
|
|
45
|
+
try {
|
|
46
|
+
spawn(cmd, [url], { stdio: "ignore", detached: true, shell: isWin }).unref();
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
/* ignore browser auto-open failures — the URL is printed above */
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=serve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve.js","sourceRoot":"","sources":["../../src/core/serve.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alkahest core data model — the implementation of ALKAHEST.md §3.
|
|
3
|
+
*
|
|
4
|
+
* `map.json` is the canonical serialization of ProductMap; the dashboard (view)
|
|
5
|
+
* and PRD generation (prd) all read this structure. If the model changes, update
|
|
6
|
+
* ALKAHEST.md first.
|
|
7
|
+
*/
|
|
8
|
+
/** A source code location — clickable to jump in an editor. */
|
|
9
|
+
export interface SourceLoc {
|
|
10
|
+
/** Path relative to the project root */
|
|
11
|
+
file: string;
|
|
12
|
+
line: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* One UI element inside a screen — something the user *sees or interacts with*.
|
|
16
|
+
* The element's *effect* (navigating to another screen / calling a backend) is
|
|
17
|
+
* NOT a Feature; it's represented as an edge (Transition / Call). (ALKAHEST.md §3)
|
|
18
|
+
*/
|
|
19
|
+
export interface Feature {
|
|
20
|
+
kind: "form" | "button" | "input" | "list" | "conditional";
|
|
21
|
+
/** Human-readable name — "Login form", "Checkout button" */
|
|
22
|
+
label: string;
|
|
23
|
+
/** Evidence: component/handler name, condition expression, etc. */
|
|
24
|
+
detail: string;
|
|
25
|
+
loc: SourceLoc;
|
|
26
|
+
}
|
|
27
|
+
/** A graph node = one screen (route/page). */
|
|
28
|
+
export interface Screen {
|
|
29
|
+
/** Stable identifier based on the route path */
|
|
30
|
+
id: string;
|
|
31
|
+
/** "/dashboard/settings" */
|
|
32
|
+
route: string;
|
|
33
|
+
/** "app/dashboard/settings/page.tsx" (relative to project root) */
|
|
34
|
+
sourceFile: string;
|
|
35
|
+
/** File content hash for incremental refresh — ALKAHEST.md §9 */
|
|
36
|
+
sourceHash: string;
|
|
37
|
+
/** Human-readable screen name */
|
|
38
|
+
title: string;
|
|
39
|
+
/** Agent-written one-liner "what the user does on this screen" — empty until set via MCP */
|
|
40
|
+
summary: string;
|
|
41
|
+
/** Agent-written PRD/requirements markdown for this screen — empty until set via MCP. Shown in the dashboard panel. */
|
|
42
|
+
prd?: string;
|
|
43
|
+
features: Feature[];
|
|
44
|
+
/** Names of the main components used on this screen */
|
|
45
|
+
components: string[];
|
|
46
|
+
/** Whether this is the app entry point (root launched by @main/App, or the "/" route). Marks the start point / layout root. */
|
|
47
|
+
isEntry?: boolean;
|
|
48
|
+
}
|
|
49
|
+
/** Layer-1 edge = navigation from screen → screen (or an external URL). */
|
|
50
|
+
export interface Transition {
|
|
51
|
+
from: string;
|
|
52
|
+
/** Target Screen.id, or an external URL, or null if not statically resolved */
|
|
53
|
+
to: string | null;
|
|
54
|
+
/**
|
|
55
|
+
* Edge kind:
|
|
56
|
+
* - "navigate": user-triggered navigation (Link/router.push/.sheet/NavigationLink, etc.)
|
|
57
|
+
* - "contains": a screen containing a child screen (TabView/embed) — structural flow, used to find the start point.
|
|
58
|
+
*/
|
|
59
|
+
kind: "navigate" | "contains";
|
|
60
|
+
/** Original expression text when unresolved (e.g. "router.push(path)") */
|
|
61
|
+
rawTarget?: string;
|
|
62
|
+
/** "<Link href>" | "router.push" | "form action" | "redirect()" | "<a href>" | "Tab"/"embed" */
|
|
63
|
+
trigger: string;
|
|
64
|
+
loc: SourceLoc;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Layer-2 node = a backend/data capability a screen *calls* (ALKAHEST.md §3).
|
|
68
|
+
* When several screens call the same resource they share one node → revealing "which screens use it together".
|
|
69
|
+
*/
|
|
70
|
+
export interface Resource {
|
|
71
|
+
/** Stable identifier based on method+path or an identifiable name */
|
|
72
|
+
id: string;
|
|
73
|
+
kind: "endpoint" | "server-action" | "rpc" | "data-source" | "external";
|
|
74
|
+
/** Human-readable name — "GET /api/orders" */
|
|
75
|
+
label: string;
|
|
76
|
+
/** HTTP method (when an endpoint) */
|
|
77
|
+
method?: string;
|
|
78
|
+
/** Path or URL — "/api/orders" */
|
|
79
|
+
path?: string;
|
|
80
|
+
}
|
|
81
|
+
/** Layer-2 edge = call from screen → resource. */
|
|
82
|
+
export interface Call {
|
|
83
|
+
from: string;
|
|
84
|
+
/** Target Resource.id, or null if not statically resolved */
|
|
85
|
+
to: string | null;
|
|
86
|
+
/** Original expression text when unresolved */
|
|
87
|
+
rawTarget?: string;
|
|
88
|
+
/** "fetch" | "useQuery" | "useMutation" | "server action" | handler name, etc. */
|
|
89
|
+
trigger: string;
|
|
90
|
+
loc: SourceLoc;
|
|
91
|
+
}
|
|
92
|
+
export type Framework = "next" | "react-router" | "vite-react" | "react-native" | "vue" | "nuxt" | "svelte" | "remix" | "astro" | "angular" | "static" | "swiftui" | "uikit" | "compose" | "flutter" | "django" | "flask" | "rails" | "unknown";
|
|
93
|
+
export type Router = "next-app" | "next-pages" | "react-router" | "expo-router" | "react-navigation" | "vue-router" | "nuxt-pages" | "sveltekit" | "remix-routes" | "astro-pages" | "angular-router" | "static-html" | "swiftui-views" | "uikit-vc" | "compose-nav" | "flutter-nav" | "django-urls" | "flask-routes" | "rails-routes" | "unknown";
|
|
94
|
+
export interface ProductMapMeta {
|
|
95
|
+
framework: Framework;
|
|
96
|
+
router: Router;
|
|
97
|
+
/** ISO 8601 — scan time */
|
|
98
|
+
scannedAt: string;
|
|
99
|
+
/** Absolute path */
|
|
100
|
+
projectRoot: string;
|
|
101
|
+
/** Incremental baseline: per-file content hashes — ALKAHEST.md §9 */
|
|
102
|
+
fileHashes: Record<string, string>;
|
|
103
|
+
/** alkahest version that produced this map */
|
|
104
|
+
alkahestVersion: string;
|
|
105
|
+
}
|
|
106
|
+
/** The full product map — the root of `.alkahest/map.json`. */
|
|
107
|
+
export interface ProductMap {
|
|
108
|
+
/** Layer-1 nodes: screens */
|
|
109
|
+
screens: Screen[];
|
|
110
|
+
/** Layer-2 nodes: resources a screen calls (API/data/server action) */
|
|
111
|
+
resources: Resource[];
|
|
112
|
+
/** Layer-1 edges: screen → screen navigation */
|
|
113
|
+
transitions: Transition[];
|
|
114
|
+
/** Layer-2 edges: screen → resource calls */
|
|
115
|
+
calls: Call[];
|
|
116
|
+
meta: ProductMapMeta;
|
|
117
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alkahest core data model — the implementation of ALKAHEST.md §3.
|
|
3
|
+
*
|
|
4
|
+
* `map.json` is the canonical serialization of ProductMap; the dashboard (view)
|
|
5
|
+
* and PRD generation (prd) all read this structure. If the model changes, update
|
|
6
|
+
* ALKAHEST.md first.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|