@justfortytwo/installer 1.0.0-5 → 1.0.0-7

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.
@@ -0,0 +1,219 @@
1
+ // runtime.ts — foreground supervisor for fortytwo's long-running services.
2
+ //
3
+ // `fortytwo start` runs the installed + configured services (the Telegram bridge,
4
+ // the scheduler daemon) as CHILD processes of one foreground process: it loads
5
+ // the project .env, spawns each service's own bin from the project's
6
+ // node_modules, prefixes and forwards their logs, and on SIGINT/SIGTERM — or as
7
+ // soon as any service exits — stops the rest and exits. It never daemonizes and
8
+ // never restarts a service: restart policy belongs to whatever runs
9
+ // `fortytwo start` (Docker/Podman, systemd, another supervisor). This is process
10
+ // lifecycle only; each service's logic stays in its own package.
11
+ //
12
+ // `.fortytwo/runtime.json` records the running supervisor (its pid, a heartbeat
13
+ // refreshed every few seconds, and its children). `status`, `stop` and `pair`
14
+ // read it, and it is removed on exit. A stale heartbeat means "not running", so a
15
+ // file left behind by a killed supervisor can never make `stop` signal a pid that
16
+ // has since been reused.
17
+ import { spawn } from 'node:child_process';
18
+ import { createInterface } from 'node:readline';
19
+ import { existsSync, readFileSync, writeFileSync, renameSync, mkdirSync, rmSync } from 'node:fs';
20
+ import { join, resolve } from 'node:path';
21
+ import { findSiblingDir } from './engine.js';
22
+ export const SERVICES = [
23
+ { name: 'telegram', pkg: '@justfortytwo/telegram', bin: 'fortytwo-telegram-bridge', requiredEnv: ['TELEGRAM_BOT_TOKEN'] },
24
+ { name: 'scheduler', pkg: '@justfortytwo/scheduler', bin: 'fortytwo-scheduler', requiredEnv: [] },
25
+ ];
26
+ /**
27
+ * The environment the services run with. Precedence: the supervisor's own
28
+ * process env (shell, container, systemd) > the project's .env > defaults.
29
+ * FORTYTWO_ROOT defaults to the project root: the bridge resolves its bindings
30
+ * db and config from it, and would otherwise fall back to its own package dir.
31
+ */
32
+ export function buildServiceEnv(processEnv, fileEnv, root) {
33
+ const env = { ...fileEnv };
34
+ for (const [k, v] of Object.entries(processEnv))
35
+ if (v !== undefined)
36
+ env[k] = v;
37
+ env.FORTYTWO_ROOT ??= resolve(root);
38
+ return env;
39
+ }
40
+ /** Which services to run: installed in the project AND configured; the rest are skipped with a reason. */
41
+ export function planServices(root, env, specs = SERVICES) {
42
+ const run = [];
43
+ const skipped = [];
44
+ for (const spec of specs) {
45
+ const dir = findSiblingDir(spec.pkg, root);
46
+ if (!dir) {
47
+ skipped.push({ name: spec.name, reason: `${spec.pkg} not installed` });
48
+ continue;
49
+ }
50
+ let bin;
51
+ try {
52
+ bin = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')).bin;
53
+ }
54
+ catch {
55
+ bin = undefined;
56
+ }
57
+ const rel = typeof bin === 'string' ? bin : bin?.[spec.bin];
58
+ if (typeof rel !== 'string' || !rel) {
59
+ skipped.push({ name: spec.name, reason: `${spec.pkg} has no ${spec.bin} bin` });
60
+ continue;
61
+ }
62
+ const missing = spec.requiredEnv.filter((k) => !env[k]);
63
+ if (missing.length > 0) {
64
+ skipped.push({ name: spec.name, reason: `${missing.join(', ')} not set` });
65
+ continue;
66
+ }
67
+ run.push({ name: spec.name, script: join(dir, rel) });
68
+ }
69
+ return { run, skipped };
70
+ }
71
+ /** A heartbeat older than this means the supervisor is gone (killed without cleanup). */
72
+ export const RUNTIME_STALE_MS = 30_000;
73
+ export function runtimeStatePath(root) {
74
+ return join(resolve(root), '.fortytwo', 'runtime.json');
75
+ }
76
+ export function readRuntimeState(root) {
77
+ try {
78
+ return JSON.parse(readFileSync(runtimeStatePath(root), 'utf8'));
79
+ }
80
+ catch {
81
+ return null;
82
+ }
83
+ }
84
+ function writeRuntimeState(root, state) {
85
+ const path = runtimeStatePath(root);
86
+ mkdirSync(join(resolve(root), '.fortytwo'), { recursive: true });
87
+ const tmp = `${path}.tmp`;
88
+ writeFileSync(tmp, JSON.stringify(state, null, 2) + '\n', 'utf8');
89
+ renameSync(tmp, path);
90
+ }
91
+ export function isPidAlive(pid) {
92
+ try {
93
+ process.kill(pid, 0);
94
+ return true;
95
+ }
96
+ catch (err) {
97
+ return err.code === 'EPERM'; // exists, owned by someone else
98
+ }
99
+ }
100
+ /** The running supervisor's state, or null if none: no file, stale heartbeat, or dead pid. */
101
+ export function liveRuntime(root, nowMs = Date.now(), alive = isPidAlive) {
102
+ const s = readRuntimeState(root);
103
+ if (!s || typeof s.pid !== 'number')
104
+ return null;
105
+ const beat = new Date(s.heartbeatAt).getTime();
106
+ if (!Number.isFinite(beat) || nowMs - beat > RUNTIME_STALE_MS)
107
+ return null;
108
+ return alive(s.pid) ? s : null;
109
+ }
110
+ /** True when a live `fortytwo start` is currently running the named service. */
111
+ export function serviceRunning(state, name) {
112
+ return !!state?.services.some((s) => s.name === name && s.state === 'running');
113
+ }
114
+ /**
115
+ * Run `services` as foreground children until a signal arrives or one of them
116
+ * exits; then stop the others (SIGTERM, then SIGKILL after graceMs) and resolve
117
+ * with the exit code: 0 for a requested stop, non-zero when a service failed.
118
+ * Children are never detached, so none outlive the supervisor's shutdown.
119
+ */
120
+ export function supervise(services, opts) {
121
+ const out = opts.out ?? ((l) => { process.stdout.write(l + '\n'); });
122
+ const err = opts.err ?? ((l) => { process.stderr.write(l + '\n'); });
123
+ const signals = opts.signals ?? process;
124
+ const graceMs = opts.graceMs ?? 10_000;
125
+ const startedAt = new Date().toISOString();
126
+ return new Promise((resolveExit) => {
127
+ const children = new Map();
128
+ const exited = new Set();
129
+ let stopping = false;
130
+ let exitCode = 0;
131
+ let killTimer;
132
+ const state = () => ({
133
+ pid: process.pid,
134
+ startedAt,
135
+ heartbeatAt: new Date().toISOString(),
136
+ services: services.map((s) => ({
137
+ name: s.name,
138
+ pid: children.get(s.name)?.pid ?? null,
139
+ state: exited.has(s.name) ? 'exited' : 'running',
140
+ })),
141
+ skipped: opts.skipped ?? [],
142
+ });
143
+ const beat = () => { try {
144
+ writeRuntimeState(opts.root, state());
145
+ }
146
+ catch { /* best-effort */ } };
147
+ const killAll = (sig) => {
148
+ for (const [name, child] of children)
149
+ if (!exited.has(name))
150
+ child.kill(sig);
151
+ };
152
+ const stop = () => {
153
+ if (stopping)
154
+ return;
155
+ stopping = true;
156
+ killAll('SIGTERM');
157
+ killTimer = setTimeout(() => killAll('SIGKILL'), graceMs);
158
+ };
159
+ const onSignal = (sig) => {
160
+ if (stopping) {
161
+ err(`[fortytwo] ${sig} again: killing services now`);
162
+ killAll('SIGKILL');
163
+ return;
164
+ }
165
+ out(`[fortytwo] ${sig} received: stopping services…`);
166
+ stop();
167
+ };
168
+ const onSigint = () => onSignal('SIGINT');
169
+ const onSigterm = () => onSignal('SIGTERM');
170
+ signals.on('SIGINT', onSigint);
171
+ signals.on('SIGTERM', onSigterm);
172
+ const heartbeat = setInterval(beat, opts.heartbeatMs ?? 5_000);
173
+ const finish = () => {
174
+ clearInterval(heartbeat);
175
+ if (killTimer)
176
+ clearTimeout(killTimer);
177
+ signals.off('SIGINT', onSigint);
178
+ signals.off('SIGTERM', onSigterm);
179
+ try {
180
+ rmSync(runtimeStatePath(opts.root), { force: true });
181
+ }
182
+ catch { /* best-effort */ }
183
+ resolveExit(exitCode);
184
+ };
185
+ const onExit = (name, code, signal) => {
186
+ if (exited.has(name))
187
+ return;
188
+ exited.add(name);
189
+ if (!stopping) {
190
+ err(`[fortytwo] ${name} exited unexpectedly (${signal ? `signal ${signal}` : `code ${code}`}); stopping fortytwo`);
191
+ exitCode = code && code !== 0 ? code : 1;
192
+ stop();
193
+ }
194
+ else {
195
+ out(`[fortytwo] ${name} stopped`);
196
+ }
197
+ beat();
198
+ if (exited.size === services.length)
199
+ finish();
200
+ };
201
+ for (const svc of services) {
202
+ const child = spawn(process.execPath, [svc.script], {
203
+ cwd: opts.root,
204
+ env: opts.env,
205
+ stdio: ['ignore', 'pipe', 'pipe'],
206
+ });
207
+ children.set(svc.name, child);
208
+ createInterface({ input: child.stdout }).on('line', (l) => out(`[${svc.name}] ${l}`));
209
+ createInterface({ input: child.stderr }).on('line', (l) => err(`[${svc.name}] ${l}`));
210
+ child.on('error', (e) => {
211
+ err(`[fortytwo] ${svc.name} failed to start: ${e.message}`);
212
+ onExit(svc.name, 1, null);
213
+ });
214
+ child.on('exit', (code, signal) => onExit(svc.name, code, signal));
215
+ }
216
+ beat();
217
+ });
218
+ }
219
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
package/dist/shim.d.ts ADDED
@@ -0,0 +1,52 @@
1
+ /** Identifies a launcher we wrote, so we only ever replace our own file. */
2
+ export declare const SHIM_MARKER = "fortytwo-shim";
3
+ export declare const SHIM_SCRIPT = "#!/bin/sh\n# fortytwo \u2014 user-level launcher installed by @justfortytwo/installer (fortytwo-shim v1).\n# It holds no version and no project path. It finds the Fortytwo project you are\n# in (the nearest directory, from here upward, that contains .fortytwo/) and runs\n# that project's own CLI, node_modules/.bin/fortytwo, from the project root.\n# Safe to delete: `npx @justfortytwo/installer init` puts it back.\nd=$(pwd -P) || exit 1\nwhile :; do\n if [ -d \"$d/.fortytwo\" ]; then\n if [ -x \"$d/node_modules/.bin/fortytwo\" ]; then\n cd \"$d\" && exec \"$d/node_modules/.bin/fortytwo\" \"$@\"\n fi\n echo \"fortytwo: $d is a Fortytwo project, but its CLI is not installed there.\" >&2\n echo \"Install it with: (cd \\\"$d\\\" && npm install @justfortytwo/installer)\" >&2\n exit 1\n fi\n [ \"$d\" = / ] && break\n d=$(dirname \"$d\")\ndone\necho \"fortytwo: not inside a Fortytwo project (no .fortytwo/ here or in any parent directory).\" >&2\necho \"Create one with: npx @justfortytwo/installer init\" >&2\nexit 1\n";
4
+ export type ShimResult = {
5
+ status: 'installed' | 'updated' | 'unchanged';
6
+ path: string;
7
+ }
8
+ /** A `fortytwo` we did not write is in the way (user file, global npm install): left alone. */
9
+ | {
10
+ status: 'foreign';
11
+ path: string;
12
+ }
13
+ /** No writable directory on PATH; nothing written. */
14
+ | {
15
+ status: 'no-dir';
16
+ } | {
17
+ status: 'unsupported';
18
+ platform: string;
19
+ };
20
+ export interface ShimEnv {
21
+ home: string;
22
+ /** The user's PATH. */
23
+ pathEnv: string;
24
+ platform: NodeJS.Platform;
25
+ /** FORTYTWO_BIN_DIR: install into exactly this directory (created if needed). */
26
+ override?: string;
27
+ /** npm's global bin directory, if known (looked up lazily, last resort). */
28
+ npmGlobalBin?: () => string | null;
29
+ }
30
+ export declare function isOurShim(path: string): boolean;
31
+ /**
32
+ * The user's own PATH entries. Entries npm adds while running a bin
33
+ * (node_modules/.bin of the project or of the npx cache) are not the user's
34
+ * PATH and vanish once the command exits, so they never count.
35
+ */
36
+ export declare function userPathDirs(pathEnv: string): string[];
37
+ /** The first executable `name` on the user's PATH, or null. */
38
+ export declare function findOnPath(name: string, pathEnv: string): string | null;
39
+ /**
40
+ * Where to put the launcher: the first of ~/.local/bin, ~/bin, npm's global bin
41
+ * directory that is already on PATH and writable. null if none is.
42
+ */
43
+ export declare function chooseShimDir(env: ShimEnv): string | null;
44
+ /**
45
+ * Install or refresh the launcher. Idempotent; never replaces a file it did not
46
+ * write. A launcher already on PATH (ours) is refreshed in place rather than
47
+ * duplicated elsewhere.
48
+ */
49
+ export declare function installShim(env: ShimEnv): ShimResult;
50
+ /** `npm prefix -g`/bin — where npm itself puts user commands (on PATH wherever npm works). */
51
+ export declare function npmGlobalBin(): string | null;
52
+ //# sourceMappingURL=shim.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shim.d.ts","sourceRoot":"","sources":["../src/shim.ts"],"names":[],"mappings":"AAmBA,4EAA4E;AAC5E,eAAO,MAAM,WAAW,kBAAkB,CAAC;AAE3C,eAAO,MAAM,WAAW,6hCAsBvB,CAAC;AAEF,MAAM,MAAM,UAAU,GAClB;IAAE,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AACjE,+FAA+F;GAC7F;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AACrC,sDAAsD;GACpD;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,GACpB;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhD,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC1B,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAM/C;AAMD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAItD;AAED,+DAA+D;AAC/D,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQvE;AAYD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAYzD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,CA4BpD;AAED,8FAA8F;AAC9F,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAI5C"}
package/dist/shim.js ADDED
@@ -0,0 +1,156 @@
1
+ // shim.ts — the user-level `fortytwo` command.
2
+ //
3
+ // `npx @justfortytwo/installer init` runs from npm's temporary exec cache, so
4
+ // nothing it brings along survives the command. init therefore (a) installs the
5
+ // CLI into the project itself (node_modules/.bin/fortytwo, pinned in
6
+ // package-lock.json) and (b) drops this tiny POSIX launcher into a directory
7
+ // that is ALREADY on the user's PATH. The launcher carries no version and no
8
+ // project path: it finds the Fortytwo project the user is in (the nearest
9
+ // directory, from cwd upward, containing .fortytwo/) and execs THAT project's
10
+ // own CLI from the project root. One launcher serves any number of projects,
11
+ // each running its own pinned CLI version.
12
+ //
13
+ // We never edit shell rc files or PATH. If no suitable directory is on PATH,
14
+ // init says so and the project-local `npx fortytwo` keeps working.
15
+ import { accessSync, chmodSync, constants, existsSync, mkdirSync, readFileSync, realpathSync, renameSync, statSync, writeFileSync } from 'node:fs';
16
+ import { spawnSync } from 'node:child_process';
17
+ import { delimiter, join, resolve } from 'node:path';
18
+ /** Identifies a launcher we wrote, so we only ever replace our own file. */
19
+ export const SHIM_MARKER = 'fortytwo-shim';
20
+ export const SHIM_SCRIPT = `#!/bin/sh
21
+ # fortytwo — user-level launcher installed by @justfortytwo/installer (${SHIM_MARKER} v1).
22
+ # It holds no version and no project path. It finds the Fortytwo project you are
23
+ # in (the nearest directory, from here upward, that contains .fortytwo/) and runs
24
+ # that project's own CLI, node_modules/.bin/fortytwo, from the project root.
25
+ # Safe to delete: \`npx @justfortytwo/installer init\` puts it back.
26
+ d=$(pwd -P) || exit 1
27
+ while :; do
28
+ if [ -d "$d/.fortytwo" ]; then
29
+ if [ -x "$d/node_modules/.bin/fortytwo" ]; then
30
+ cd "$d" && exec "$d/node_modules/.bin/fortytwo" "$@"
31
+ fi
32
+ echo "fortytwo: $d is a Fortytwo project, but its CLI is not installed there." >&2
33
+ echo "Install it with: (cd \\"$d\\" && npm install @justfortytwo/installer)" >&2
34
+ exit 1
35
+ fi
36
+ [ "$d" = / ] && break
37
+ d=$(dirname "$d")
38
+ done
39
+ echo "fortytwo: not inside a Fortytwo project (no .fortytwo/ here or in any parent directory)." >&2
40
+ echo "Create one with: npx @justfortytwo/installer init" >&2
41
+ exit 1
42
+ `;
43
+ export function isOurShim(path) {
44
+ try {
45
+ return readFileSync(path, 'utf8').slice(0, 512).includes(SHIM_MARKER);
46
+ }
47
+ catch {
48
+ return false;
49
+ }
50
+ }
51
+ function canonical(p) {
52
+ try {
53
+ return realpathSync(p);
54
+ }
55
+ catch {
56
+ return resolve(p);
57
+ }
58
+ }
59
+ /**
60
+ * The user's own PATH entries. Entries npm adds while running a bin
61
+ * (node_modules/.bin of the project or of the npx cache) are not the user's
62
+ * PATH and vanish once the command exits, so they never count.
63
+ */
64
+ export function userPathDirs(pathEnv) {
65
+ return pathEnv
66
+ .split(delimiter)
67
+ .filter((d) => d && !/[\\/]node_modules[\\/]\.bin[\\/]?$/.test(d) && !/[\\/]_npx[\\/]/.test(d));
68
+ }
69
+ /** The first executable `name` on the user's PATH, or null. */
70
+ export function findOnPath(name, pathEnv) {
71
+ for (const dir of userPathDirs(pathEnv)) {
72
+ const p = join(dir, name);
73
+ try {
74
+ if (statSync(p).isFile()) {
75
+ accessSync(p, constants.X_OK);
76
+ return p;
77
+ }
78
+ }
79
+ catch { /* not here */ }
80
+ }
81
+ return null;
82
+ }
83
+ function writableDir(dir) {
84
+ try {
85
+ mkdirSync(dir, { recursive: true });
86
+ accessSync(dir, constants.W_OK);
87
+ return true;
88
+ }
89
+ catch {
90
+ return false;
91
+ }
92
+ }
93
+ /**
94
+ * Where to put the launcher: the first of ~/.local/bin, ~/bin, npm's global bin
95
+ * directory that is already on PATH and writable. null if none is.
96
+ */
97
+ export function chooseShimDir(env) {
98
+ const onPath = new Set(userPathDirs(env.pathEnv).map(canonical));
99
+ const candidates = [
100
+ () => join(env.home, '.local', 'bin'),
101
+ () => join(env.home, 'bin'),
102
+ () => env.npmGlobalBin?.() ?? null,
103
+ ];
104
+ for (const next of candidates) {
105
+ const dir = next();
106
+ if (dir && onPath.has(canonical(dir)) && writableDir(dir))
107
+ return dir;
108
+ }
109
+ return null;
110
+ }
111
+ /**
112
+ * Install or refresh the launcher. Idempotent; never replaces a file it did not
113
+ * write. A launcher already on PATH (ours) is refreshed in place rather than
114
+ * duplicated elsewhere.
115
+ */
116
+ export function installShim(env) {
117
+ if (env.platform === 'win32')
118
+ return { status: 'unsupported', platform: env.platform };
119
+ let target;
120
+ if (env.override) {
121
+ if (!writableDir(env.override))
122
+ return { status: 'no-dir' };
123
+ target = join(env.override, 'fortytwo');
124
+ }
125
+ else {
126
+ const existing = findOnPath('fortytwo', env.pathEnv);
127
+ if (existing) {
128
+ if (!isOurShim(existing))
129
+ return { status: 'foreign', path: existing };
130
+ target = existing;
131
+ }
132
+ else {
133
+ const dir = chooseShimDir(env);
134
+ if (!dir)
135
+ return { status: 'no-dir' };
136
+ target = join(dir, 'fortytwo');
137
+ }
138
+ }
139
+ const present = existsSync(target);
140
+ if (present && !isOurShim(target))
141
+ return { status: 'foreign', path: target };
142
+ if (present && readFileSync(target, 'utf8') === SHIM_SCRIPT)
143
+ return { status: 'unchanged', path: target };
144
+ const tmp = `${target}.${process.pid}.tmp`;
145
+ writeFileSync(tmp, SHIM_SCRIPT, { encoding: 'utf8', mode: 0o755 });
146
+ chmodSync(tmp, 0o755);
147
+ renameSync(tmp, target);
148
+ return { status: present ? 'updated' : 'installed', path: target };
149
+ }
150
+ /** `npm prefix -g`/bin — where npm itself puts user commands (on PATH wherever npm works). */
151
+ export function npmGlobalBin() {
152
+ const res = spawnSync('npm', ['prefix', '-g'], { encoding: 'utf8' });
153
+ const prefix = res.status === 0 ? res.stdout.trim() : '';
154
+ return prefix ? join(prefix, 'bin') : null;
155
+ }
156
+ //# sourceMappingURL=shim.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shim.js","sourceRoot":"","sources":["../src/shim.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@justfortytwo/installer",
3
- "version": "1.0.0-5",
3
+ "version": "1.0.0-7",
4
4
  "description": "All-in-one installer and lifecycle CLI for fortytwo — scaffolds the persona surface and provisions the npm engine (memory MCP, safety gate, channel adapters, embedder).",
5
5
  "license": "MIT",
6
6
  "author": {