@agent-workshop/adoc-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/LICENSE +5 -0
  2. package/THIRD_PARTY_NOTICES.md +49 -0
  3. package/dist/claim.d.ts +17 -0
  4. package/dist/claim.js +35 -0
  5. package/dist/claim.js.map +1 -0
  6. package/dist/client.d.ts +14 -0
  7. package/dist/client.js +49 -0
  8. package/dist/client.js.map +1 -0
  9. package/dist/config.d.ts +39 -0
  10. package/dist/config.js +110 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/errors.d.ts +6 -0
  13. package/dist/errors.js +13 -0
  14. package/dist/errors.js.map +1 -0
  15. package/dist/fetch.d.ts +19 -0
  16. package/dist/fetch.js +106 -0
  17. package/dist/fetch.js.map +1 -0
  18. package/dist/git.d.ts +1 -0
  19. package/dist/git.js +13 -0
  20. package/dist/git.js.map +1 -0
  21. package/dist/herdr.d.ts +44 -0
  22. package/dist/herdr.js +134 -0
  23. package/dist/herdr.js.map +1 -0
  24. package/dist/home.d.ts +12 -0
  25. package/dist/home.js +43 -0
  26. package/dist/home.js.map +1 -0
  27. package/dist/index.d.ts +18 -0
  28. package/dist/index.js +19 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/messages.d.ts +76 -0
  31. package/dist/messages.js +119 -0
  32. package/dist/messages.js.map +1 -0
  33. package/dist/names.d.ts +14 -0
  34. package/dist/names.js +19 -0
  35. package/dist/names.js.map +1 -0
  36. package/dist/plugins.d.ts +43 -0
  37. package/dist/plugins.js +157 -0
  38. package/dist/plugins.js.map +1 -0
  39. package/dist/registry.d.ts +11 -0
  40. package/dist/registry.js +39 -0
  41. package/dist/registry.js.map +1 -0
  42. package/dist/report.d.ts +3 -0
  43. package/dist/report.js +9 -0
  44. package/dist/report.js.map +1 -0
  45. package/dist/scan.d.ts +35 -0
  46. package/dist/scan.js +163 -0
  47. package/dist/scan.js.map +1 -0
  48. package/dist/server.d.ts +80 -0
  49. package/dist/server.js +576 -0
  50. package/dist/server.js.map +1 -0
  51. package/dist/skills.d.ts +46 -0
  52. package/dist/skills.js +131 -0
  53. package/dist/skills.js.map +1 -0
  54. package/dist/terminal.d.ts +28 -0
  55. package/dist/terminal.js +110 -0
  56. package/dist/terminal.js.map +1 -0
  57. package/dist/transports.d.ts +21 -0
  58. package/dist/transports.js +69 -0
  59. package/dist/transports.js.map +1 -0
  60. package/dist/workspace.d.ts +182 -0
  61. package/dist/workspace.js +392 -0
  62. package/dist/workspace.js.map +1 -0
  63. package/package.json +54 -0
  64. package/skill/SKILL.md +219 -0
@@ -0,0 +1,157 @@
1
+ import { access, readFile } from 'node:fs/promises';
2
+ import { createRequire, registerHooks } from 'node:module';
3
+ import { dirname, join, relative, resolve } from 'node:path';
4
+ import { pathToFileURL } from 'node:url';
5
+ import semver from 'semver';
6
+ import { parse } from 'yaml';
7
+ import { errorMessage } from './errors.js';
8
+ const KIT = '@agent-workshop/adoc-plugin-kit';
9
+ // A plugin imports `@agent-workshop/adoc-plugin-kit` of the running adoc wherever its folder is, also outside any node_modules tree
10
+ // that has the kit (for example in the user _Plugin_Directory_).
11
+ registerHooks({
12
+ resolve(specifier, context, next) {
13
+ if (specifier === KIT || specifier.startsWith(`${KIT}/`))
14
+ return next(specifier, { ...context, parentURL: import.meta.url });
15
+ return next(specifier, context);
16
+ },
17
+ });
18
+ async function exists(path) {
19
+ try {
20
+ await access(path);
21
+ return true;
22
+ }
23
+ catch {
24
+ return false;
25
+ }
26
+ }
27
+ /** The _Plugin_Directory_ next to the config file whose folder is `base`. */
28
+ export function pluginDirectory(base) {
29
+ return join(base, 'plugins');
30
+ }
31
+ /** `github:<owner>/<repo>[/<folder>][#<ref>]`, or undefined for any other source. */
32
+ export function parseGithubSource(source) {
33
+ const m = /^github:([^/#\s]+)\/([^/#\s]+)((?:\/[^#\s]+)?)(?:#(\S+))?$/.exec(source);
34
+ if (!m)
35
+ return undefined;
36
+ return { owner: m[1], repo: m[2], folder: m[3].replace(/^\/|\/$/g, ''), ...(m[4] ? { ref: m[4] } : {}) };
37
+ }
38
+ /** The folder a GitHub _Plugin_Source_ is fetched to: the plugin key in lowercase, in the _Plugin_Directory_. */
39
+ export function fetchedFolder(plugin) {
40
+ return join(pluginDirectory(plugin.base), plugin.key.toLowerCase());
41
+ }
42
+ async function entryIn(folder) {
43
+ for (const candidate of [join(folder, 'index.ts'), join(folder, 'index.js'), join(folder, 'index.mjs')]) {
44
+ if (await exists(candidate))
45
+ return candidate;
46
+ }
47
+ return undefined;
48
+ }
49
+ /** The plugin folder and its entry file for a _Plugin_Source_. */
50
+ async function locate(plugin) {
51
+ const { source, base } = plugin;
52
+ if (source.startsWith('npm:')) {
53
+ const spec = source.slice(4);
54
+ const name = spec.startsWith('@') ? `@${spec.slice(1).split('@')[0]}` : spec.split('@')[0];
55
+ const range = spec.slice(name.length + 1) || undefined;
56
+ // As Node resolves it from the declaring file's folder upwards, then from the running adoc's installation.
57
+ for (const from of [join(base, 'adoc.yaml'), import.meta.url]) {
58
+ let manifest;
59
+ try {
60
+ manifest = createRequire(from).resolve(`${name}/package.json`);
61
+ }
62
+ catch {
63
+ continue;
64
+ }
65
+ const directory = dirname(manifest);
66
+ const { version } = JSON.parse(await readFile(manifest, 'utf8'));
67
+ if (range && version && !semver.satisfies(version, range, { includePrerelease: true })) {
68
+ throw new Error(`${name} ${version} in ${directory} does not satisfy ${range}`);
69
+ }
70
+ return { directory, entry: createRequire(manifest).resolve(name) };
71
+ }
72
+ throw new Error(`no npm package ${name} near ${base} or in adoc's installation; install it with npm`);
73
+ }
74
+ if (source.startsWith('github:')) {
75
+ if (!parseGithubSource(source))
76
+ throw new Error(`${source} is not github:<owner>/<repo>[/<folder>][#<ref>]`);
77
+ const directory = fetchedFolder(plugin);
78
+ const entry = await entryIn(directory);
79
+ if (!entry)
80
+ throw new Error(`${source} is not fetched into ${directory} yet; run adoc plugin install`);
81
+ return { directory, entry };
82
+ }
83
+ if (source.startsWith('./') || source.startsWith('../') || source.startsWith('/')) {
84
+ const directory = resolve(base, source);
85
+ const entry = await entryIn(directory);
86
+ if (!entry)
87
+ throw new Error(`no index.ts or index.js in ${directory}`);
88
+ return { directory, entry };
89
+ }
90
+ throw new Error(`${source} is not a plugin source; write npm:<package>, github:<owner>/<repo>/<folder>, or a path starting with ./, ../ or /`);
91
+ }
92
+ /** Fails when the plugin's `peerDependencies` range of the _Plugin_Kit_ excludes the running one. */
93
+ async function checkKit(directory) {
94
+ let manifest;
95
+ try {
96
+ manifest = JSON.parse(await readFile(join(directory, 'package.json'), 'utf8'));
97
+ }
98
+ catch {
99
+ return;
100
+ }
101
+ const range = manifest.peerDependencies?.[KIT];
102
+ if (!range)
103
+ return;
104
+ const { version } = JSON.parse(await readFile(createRequire(import.meta.url).resolve(`${KIT}/package.json`), 'utf8'));
105
+ if (!semver.satisfies(version, range, { includePrerelease: true }))
106
+ throw new Error(`the plugin needs ${KIT} ${range}, but this adoc has ${version}; update adoc or the plugin`);
107
+ }
108
+ export function scopeOf(home, path) {
109
+ const rel = relative(home.workspace, path);
110
+ return rel && !rel.startsWith('..') && !rel.startsWith('/') ? 'project' : 'user';
111
+ }
112
+ /** Reads the `skill/SKILL.md` of an owner folder; throws when it is missing or has no name and description. */
113
+ export async function readSkillSource(owner, scope) {
114
+ const directory = join(owner, 'skill');
115
+ let text;
116
+ try {
117
+ text = await readFile(join(directory, 'SKILL.md'), 'utf8');
118
+ }
119
+ catch {
120
+ throw new Error(`no skill/SKILL.md in ${owner}; every plugin needs its agent skill there`);
121
+ }
122
+ const front = /^---\r?\n([\s\S]*?)\r?\n---/.exec(text);
123
+ const data = (front ? parse(front[1]) : undefined);
124
+ if (typeof data?.name !== 'string' || typeof data.description !== 'string')
125
+ throw new Error(`${join(directory, 'SKILL.md')} needs front matter with name and description`);
126
+ return { name: data.name, description: data.description, directory, scope };
127
+ }
128
+ let loadCounter = 0;
129
+ async function loadOne(home, plugin, fresh) {
130
+ const { key, source } = plugin;
131
+ let directory;
132
+ try {
133
+ const located = await locate(plugin);
134
+ directory = located.directory;
135
+ const entry = located.entry;
136
+ await checkKit(directory);
137
+ const skill = await readSkillSource(directory, scopeOf(home, directory));
138
+ const url = pathToFileURL(entry);
139
+ if (fresh)
140
+ url.searchParams.set('adoc-load', String(++loadCounter));
141
+ const module = (await import(url.href));
142
+ if (!module.default)
143
+ throw new Error(`${entry} has no default export; write export default definePlugin({ … })`);
144
+ return { key, source, directory, definition: module.default, skill };
145
+ }
146
+ catch (error) {
147
+ return { key, source, ...(directory ? { directory } : {}), error: errorMessage(error) };
148
+ }
149
+ }
150
+ /** Loads every plugin declared in the _Adoc_Config_. A failure is kept as the plugin's error, never thrown. */
151
+ export async function loadPlugins(home, config, fresh = false) {
152
+ const loaded = new Map();
153
+ for (const declared of config.plugins)
154
+ loaded.set(declared.key, await loadOne(home, declared, fresh));
155
+ return loaded;
156
+ }
157
+ //# sourceMappingURL=plugins.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugins.js","sourceRoot":"","sources":["../src/plugins.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /** _Server_Record_: what a running _Adoc_Server_ writes outside the repository. */
2
+ export interface ServerRecord {
3
+ pid: number;
4
+ url: string;
5
+ workspace: string;
6
+ }
7
+ /** The record of the running server of a workspace, or undefined when none runs. */
8
+ export declare function readServerRecord(workspace: string, env?: NodeJS.ProcessEnv): Promise<ServerRecord | undefined>;
9
+ export declare function writeServerRecord(record: ServerRecord, env?: NodeJS.ProcessEnv): Promise<void>;
10
+ /** Removes the record when it still belongs to this process. */
11
+ export declare function removeServerRecord(workspace: string, env?: NodeJS.ProcessEnv): Promise<void>;
@@ -0,0 +1,39 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ function recordPath(workspace, env) {
6
+ const base = env.XDG_RUNTIME_DIR || tmpdir();
7
+ return join(base, 'adoc', `${createHash('sha256').update(workspace).digest('hex').slice(0, 16)}.json`);
8
+ }
9
+ function alive(pid) {
10
+ try {
11
+ process.kill(pid, 0);
12
+ return true;
13
+ }
14
+ catch (error) {
15
+ return error.code === 'EPERM';
16
+ }
17
+ }
18
+ /** The record of the running server of a workspace, or undefined when none runs. */
19
+ export async function readServerRecord(workspace, env = process.env) {
20
+ try {
21
+ const record = JSON.parse(await readFile(recordPath(workspace, env), 'utf8'));
22
+ return record.workspace === workspace && alive(record.pid) ? record : undefined;
23
+ }
24
+ catch {
25
+ return undefined;
26
+ }
27
+ }
28
+ export async function writeServerRecord(record, env = process.env) {
29
+ const path = recordPath(record.workspace, env);
30
+ await mkdir(join(path, '..'), { recursive: true });
31
+ await writeFile(path, JSON.stringify(record) + '\n');
32
+ }
33
+ /** Removes the record when it still belongs to this process. */
34
+ export async function removeServerRecord(workspace, env = process.env) {
35
+ const current = await readServerRecord(workspace, env);
36
+ if (!current || current.pid === process.pid)
37
+ await rm(recordPath(workspace, env), { force: true });
38
+ }
39
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AASjC,SAAS,UAAU,CAAC,SAAiB,EAAE,GAAsB;IAC3D,MAAM,IAAI,GAAG,GAAG,CAAC,eAAe,IAAI,MAAM,EAAE,CAAC;IAC7C,OAAO,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;AACzG,CAAC;AAED,SAAS,KAAK,CAAC,GAAW;IACxB,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAQ,KAA+B,CAAC,IAAI,KAAK,OAAO,CAAC;IAC3D,CAAC;AACH,CAAC;AAED,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,SAAiB,EAAE,GAAG,GAAsB,OAAO,CAAC,GAAG;IAC5F,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,UAAU,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,CAAiB,CAAC;QAC9F,OAAO,MAAM,CAAC,SAAS,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IAClF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAAoB,EAAE,GAAG,GAAsB,OAAO,CAAC,GAAG;IAChG,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAC/C,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACvD,CAAC;AAED,gEAAgE;AAChE,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAiB,EAAE,GAAG,GAAsB,OAAO,CAAC,GAAG;IAC9F,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IACvD,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,KAAK,OAAO,CAAC,GAAG;QAAE,MAAM,EAAE,CAAC,UAAU,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AACrG,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { CheckEntry } from './workspace.js';
2
+ /** Renders the report of _Adoc_Check_Command_ as text, one line per entry. */
3
+ export declare function formatCheck(entries: readonly CheckEntry[]): string;
package/dist/report.js ADDED
@@ -0,0 +1,9 @@
1
+ /** Renders the report of _Adoc_Check_Command_ as text, one line per entry. */
2
+ export function formatCheck(entries) {
3
+ if (!entries.length)
4
+ return 'adoc check: no problems';
5
+ const errors = entries.filter((e) => e.level === 'error').length;
6
+ const lines = entries.map((e) => `${e.level.padEnd(7)} ${e.kind.padEnd(18)} ${e.message}`);
7
+ return `adoc check: ${errors} error(s), ${entries.length - errors} warning(s)\n${lines.join('\n')}`;
8
+ }
9
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAEA,8EAA8E;AAC9E,MAAM,UAAU,WAAW,CAAC,OAA8B;IACxD,IAAI,CAAC,OAAO,CAAC,MAAM;QAAE,OAAO,yBAAyB,CAAC;IACtD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;IACjE,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAC3F,OAAO,eAAe,MAAM,cAAc,OAAO,CAAC,MAAM,GAAG,MAAM,gBAAgB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AACtG,CAAC"}
package/dist/scan.d.ts ADDED
@@ -0,0 +1,35 @@
1
+ import type { PluginDocument } from '@agent-workshop/adoc-plugin-kit';
2
+ import type { LoadedPlugin } from './plugins.js';
3
+ /** Where one _Document_ lives. Paths are workspace-relative with forward slashes. */
4
+ export interface DocumentRecord {
5
+ readonly key: string;
6
+ readonly pluginKey: string;
7
+ readonly localId: string;
8
+ readonly kind: 'file' | 'folder';
9
+ readonly path: string;
10
+ readonly file: string;
11
+ /** Inside a _Document_Archive_: a folder named `_archive` at any depth of a watch path. */
12
+ readonly archived: boolean;
13
+ /** The companion files of a file document that exist, such as `docs/SKETCH-login.png`. */
14
+ readonly companions: readonly string[];
15
+ }
16
+ /** The folder name of a _Document_Archive_. */
17
+ export declare const ARCHIVE_FOLDER = "_archive";
18
+ export interface ScanProblem {
19
+ readonly kind: 'duplicate-key' | 'unknown-plugin-key' | 'invalid-local-id' | 'layout-mismatch';
20
+ readonly message: string;
21
+ readonly path: string;
22
+ readonly key?: string;
23
+ }
24
+ export interface ScanResult {
25
+ readonly documents: Map<string, DocumentRecord>;
26
+ readonly problems: ScanProblem[];
27
+ }
28
+ /** Finds every _Document_ under the _Watch_Path_ entries. A file under overlapping watch paths counts once. */
29
+ export declare function scanDocuments(workspace: string, watch: readonly string[], plugins: Map<string, LoadedPlugin>): Promise<ScanResult>;
30
+ /** Reads a document into the shape plugins receive, together with its _Document_Version_ and its last update (the newest file modification time). */
31
+ export declare function readDocument(workspace: string, record: DocumentRecord): Promise<{
32
+ doc: PluginDocument;
33
+ version: string;
34
+ updatedAt: string;
35
+ }>;
package/dist/scan.js ADDED
@@ -0,0 +1,163 @@
1
+ import { readdir, readFile, stat } from 'node:fs/promises';
2
+ import { createHash } from 'node:crypto';
3
+ import { join, relative, resolve, sep } from 'node:path';
4
+ import { KEY_PREFIX_PATTERN, LOCAL_ID_PATTERN } from './names.js';
5
+ /** The folder name of a _Document_Archive_. */
6
+ export const ARCHIVE_FOLDER = '_archive';
7
+ const toPosix = (path) => path.split(sep).join('/');
8
+ async function isDirectory(path) {
9
+ try {
10
+ return (await stat(path)).isDirectory();
11
+ }
12
+ catch {
13
+ return false;
14
+ }
15
+ }
16
+ /** Finds every _Document_ under the _Watch_Path_ entries. A file under overlapping watch paths counts once. */
17
+ export async function scanDocuments(workspace, watch, plugins) {
18
+ const documents = new Map();
19
+ const problems = [];
20
+ const seen = new Set();
21
+ /** Companion files found, by the path their document would have. */
22
+ const companions = new Map();
23
+ const visit = async (directory, archived) => {
24
+ let entries;
25
+ try {
26
+ entries = await readdir(directory, { withFileTypes: true });
27
+ }
28
+ catch {
29
+ return;
30
+ }
31
+ entries.sort((a, b) => a.name.localeCompare(b.name));
32
+ for (const entry of entries) {
33
+ if (entry.name.startsWith('.') || entry.name === 'node_modules')
34
+ continue;
35
+ const absolute = join(directory, entry.name);
36
+ if (seen.has(absolute))
37
+ continue;
38
+ seen.add(absolute);
39
+ const relPath = toPosix(relative(workspace, absolute));
40
+ const isDir = entry.isDirectory();
41
+ const match = KEY_PREFIX_PATTERN.exec(entry.name);
42
+ if (!match) {
43
+ if (isDir)
44
+ await visit(absolute, archived || entry.name === ARCHIVE_FOLDER);
45
+ continue;
46
+ }
47
+ const pluginKey = match[1];
48
+ const plugin = plugins.get(pluginKey);
49
+ if (!plugin) {
50
+ problems.push({ kind: 'unknown-plugin-key', path: relPath, message: `${relPath} looks like a document key, but no plugin is declared with the key ${pluginKey}.` });
51
+ continue;
52
+ }
53
+ if (!plugin.definition)
54
+ continue;
55
+ const layout = plugin.definition.layout;
56
+ let localId;
57
+ let file;
58
+ if (layout.kind === 'file') {
59
+ const companion = isDir ? undefined : layout.companions?.find((ext) => entry.name.endsWith(ext));
60
+ if (companion) {
61
+ const main = `${relPath.slice(0, -companion.length)}${layout.extension}`;
62
+ companions.set(main, [...(companions.get(main) ?? []), relPath]);
63
+ continue;
64
+ }
65
+ if (isDir || !entry.name.endsWith(layout.extension)) {
66
+ problems.push({ kind: 'layout-mismatch', path: relPath, message: `${relPath}: ${pluginKey} documents are files ending with ${layout.extension}.` });
67
+ continue;
68
+ }
69
+ localId = match[2].slice(0, -layout.extension.length);
70
+ file = relPath;
71
+ }
72
+ else {
73
+ if (!isDir) {
74
+ problems.push({ kind: 'layout-mismatch', path: relPath, message: `${relPath}: ${pluginKey} documents are folders with ${layout.entry} inside.` });
75
+ continue;
76
+ }
77
+ localId = match[2];
78
+ file = `${relPath}/${layout.entry}`;
79
+ }
80
+ const key = `${pluginKey}-${localId}`;
81
+ if (!LOCAL_ID_PATTERN.test(localId)) {
82
+ problems.push({ kind: 'invalid-local-id', path: relPath, key, message: `${relPath}: the local id "${localId}" may use only lowercase letters, digits, hyphens, underscores and dots.` });
83
+ continue;
84
+ }
85
+ const record = { key, pluginKey, localId, kind: layout.kind, path: relPath, file, archived, companions: [] };
86
+ const existing = documents.get(key);
87
+ if (existing) {
88
+ // The not archived document wins, whichever the scan met first.
89
+ const used = existing.archived && !archived ? record : existing;
90
+ const other = used === record ? existing : record;
91
+ documents.set(key, used);
92
+ problems.push({ kind: 'duplicate-key', path: other.path, key, message: `${key} is carried by both ${used.path} and ${other.path}; ${used.path} is used.` });
93
+ continue;
94
+ }
95
+ documents.set(key, record);
96
+ }
97
+ };
98
+ for (const path of watch)
99
+ await visit(resolve(workspace, path), false);
100
+ for (const [main, paths] of companions) {
101
+ const record = [...documents.values()].find((d) => d.path === main);
102
+ if (record)
103
+ documents.set(record.key, { ...record, companions: paths.sort() });
104
+ else
105
+ for (const path of paths)
106
+ problems.push({ kind: 'layout-mismatch', path, message: `${path} is a companion file, but its document ${main} does not exist.` });
107
+ }
108
+ return { documents, problems };
109
+ }
110
+ async function listFiles(root, prefix = '') {
111
+ const out = [];
112
+ for (const entry of await readdir(join(root, prefix), { withFileTypes: true })) {
113
+ const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
114
+ if (entry.isDirectory())
115
+ out.push(...(await listFiles(root, rel)));
116
+ else
117
+ out.push(rel);
118
+ }
119
+ return out.sort();
120
+ }
121
+ /** Reads a document into the shape plugins receive, together with its _Document_Version_ and its last update (the newest file modification time). */
122
+ export async function readDocument(workspace, record) {
123
+ const files = {};
124
+ const absolute = join(workspace, record.path);
125
+ let updated = 0;
126
+ const read = async (path) => {
127
+ updated = Math.max(updated, (await stat(path)).mtimeMs);
128
+ return readFile(path, 'utf8');
129
+ };
130
+ if (record.kind === 'file') {
131
+ files[record.path.split('/').pop()] = await read(absolute);
132
+ }
133
+ else if (await isDirectory(absolute)) {
134
+ for (const rel of await listFiles(absolute))
135
+ files[rel] = await read(join(absolute, rel));
136
+ }
137
+ const mainName = record.kind === 'file' ? record.path.split('/').pop() : record.file.slice(record.path.length + 1);
138
+ const hash = createHash('sha256');
139
+ for (const name of Object.keys(files).sort())
140
+ hash.update(name).update('\0').update(files[name]).update('\0');
141
+ // Companion files count for the version and the last update, but plugins do not receive them: they may be binary.
142
+ for (const path of record.companions) {
143
+ try {
144
+ const absoluteCompanion = join(workspace, path);
145
+ updated = Math.max(updated, (await stat(absoluteCompanion)).mtimeMs);
146
+ hash.update(path).update('\0').update(await readFile(absoluteCompanion)).update('\0');
147
+ }
148
+ catch {
149
+ // A companion removed since the scan; the next scan drops it.
150
+ }
151
+ }
152
+ const doc = {
153
+ key: record.key,
154
+ pluginKey: record.pluginKey,
155
+ localId: record.localId,
156
+ path: record.path,
157
+ file: record.file,
158
+ text: files[mainName] ?? '',
159
+ files,
160
+ };
161
+ return { doc, version: hash.digest('hex').slice(0, 16), updatedAt: new Date(updated).toISOString() };
162
+ }
163
+ //# sourceMappingURL=scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ import { type IncomingMessage, type ServerResponse } from 'node:http';
2
+ import { MessageQueue, type UserMessage } from './messages.js';
3
+ import { type MessageTransport } from './transports.js';
4
+ import type { Workspace } from './workspace.js';
5
+ export declare const PROTOCOL = "adoc/1";
6
+ /** A _Browser_Session_ as the server tracks it. */
7
+ export interface BrowserSession {
8
+ id: string;
9
+ connected: boolean;
10
+ lastAccess: string;
11
+ location: string;
12
+ }
13
+ /** Handles a request outside adoc's own routes, such as `/mcp`. Returns true when it handled the request. */
14
+ export type ServerExtension = (request: IncomingMessage, response: ServerResponse) => Promise<boolean>;
15
+ export interface ServerOptions {
16
+ host?: string;
17
+ port?: number;
18
+ extensions?: ServerExtension[];
19
+ log?: (line: string) => void;
20
+ debounceMs?: number;
21
+ }
22
+ export declare function publicMessage(message: UserMessage): {
23
+ formatted: string;
24
+ };
25
+ /**
26
+ * _Adoc_Server_: serves the _Adoc_Web_UI_, the REST API and live events for one workspace,
27
+ * watches its files and holds every _User_Message_ until delivery.
28
+ */
29
+ export declare class AdocServer {
30
+ readonly workspace: Workspace;
31
+ private readonly options;
32
+ readonly queue: MessageQueue;
33
+ readonly transport: MessageTransport;
34
+ private readonly listener;
35
+ private readonly sockets;
36
+ private watchers;
37
+ private readonly sessions;
38
+ private claim;
39
+ private agentStatus;
40
+ private unsubscribe;
41
+ private retryHeld;
42
+ private readonly terminal;
43
+ private debounce;
44
+ private chain;
45
+ private readonly host;
46
+ private readonly port;
47
+ private readonly log;
48
+ private readonly webappDirectory;
49
+ constructor(workspace: Workspace, options?: ServerOptions);
50
+ get url(): string;
51
+ start(): Promise<void>;
52
+ stop(): Promise<void>;
53
+ /** Serializes workspace work so that rescans and actions never overlap. */
54
+ private run;
55
+ private pluginDebounce;
56
+ private schedulePluginReload;
57
+ private schedule;
58
+ /** _Document_Change_Notification_: rescans and tells browsers which documents changed. */
59
+ rescan(): Promise<void>;
60
+ private welcome;
61
+ /** Reads `.adoc/claim.yaml`, follows the claimed pane's agent status, and retries held messages. */
62
+ private loadClaim;
63
+ /** The assigned agent as the web UI shows it. */
64
+ agentInfo(): Record<string, unknown>;
65
+ private broadcastAgent;
66
+ /** Every _Browser_Session_, most recent access first. */
67
+ browserSessions(): BrowserSession[];
68
+ /** Sends a browser session to a document, an anchor or a plugin; by default the connected session accessed last. */
69
+ openInBrowser(target: string, sessionId?: string): {
70
+ session: string;
71
+ location: string;
72
+ };
73
+ private broadcast;
74
+ private handle;
75
+ /**
76
+ * Serves a built file under `/assets/` (the `client/` folder of a plugin under `/assets/plugins/<KEY>/`); every other
77
+ * path is a client route and gets index.html.
78
+ */
79
+ private serveWebapp;
80
+ }