@jenga-ai/agent 3.2.0 → 3.5.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 (68) hide show
  1. package/README.md +52 -12
  2. package/agents/developer.md +16 -1
  3. package/agents/scrum-master.md +1 -0
  4. package/bin/jenga.js +10 -0
  5. package/lib/commands/dashboard.js +92 -0
  6. package/lib/skill-allow-list.json +6 -2
  7. package/package.json +21 -2
  8. package/project/app/api/lib/resolve-project-root.js +120 -0
  9. package/project/app/api/package.json +16 -0
  10. package/project/app/api/parsers/architecture.js +72 -0
  11. package/project/app/api/parsers/board.js +141 -0
  12. package/project/app/api/parsers/documentation.js +125 -0
  13. package/project/app/api/parsers/git-log.js +52 -0
  14. package/project/app/api/parsers/ideas.js +62 -0
  15. package/project/app/api/parsers/knowledge-graph.js +73 -0
  16. package/project/app/api/parsers/lib/markdown-dir-reader.js +163 -0
  17. package/project/app/api/parsers/rapports.js +148 -0
  18. package/project/app/api/parsers/todo.js +179 -0
  19. package/project/app/api/response.js +47 -0
  20. package/project/app/api/routes/architecture.js +23 -0
  21. package/project/app/api/routes/board.js +46 -0
  22. package/project/app/api/routes/documentation.js +24 -0
  23. package/project/app/api/routes/health.js +25 -0
  24. package/project/app/api/routes/history.js +55 -0
  25. package/project/app/api/routes/rapports.js +24 -0
  26. package/project/app/api/scripts/capture-snapshot.js +294 -0
  27. package/project/app/api/server.js +112 -0
  28. package/project/app/api/types.js +40 -0
  29. package/project/app/package.json +21 -0
  30. package/project/app/ui/dist/assets/index-7fj-vllY.js +104 -0
  31. package/project/app/ui/dist/assets/index-CdK3Qrep.css +1 -0
  32. package/project/app/ui/dist/index.html +13 -0
  33. package/project/app/ui/package.json +23 -0
  34. package/project/app/ui/scripts/build-snapshot-html.cjs +214 -0
  35. package/project/app/ui/scripts/dashboard-open.cjs +88 -0
  36. package/project/app/ui/scripts/dashboard-start.cjs +87 -0
  37. package/scripts/acquire-concurrency-slot.sh +220 -0
  38. package/scripts/compute-deploy-reconcile.sh +439 -0
  39. package/scripts/jenga-permission-level-switch.sh +19 -3
  40. package/scripts/mark-deployed.sh +532 -0
  41. package/scripts/populate-knowledge-graph.js +429 -0
  42. package/scripts/release-concurrency-slot.sh +129 -0
  43. package/scripts/validate-board.sh +60 -2
  44. package/scripts/verify-consumer-install.sh +470 -0
  45. package/skills/j-cloud-connect/SKILL.md +95 -0
  46. package/skills/j-cloud-connect/scripts/configure-backend.sh +267 -0
  47. package/skills/j-cloud-connect/scripts/install-rclone.sh +153 -0
  48. package/skills/j-dashboard/SKILL.md +144 -0
  49. package/skills/j-dashboard/scripts/launch.sh +121 -0
  50. package/skills/j-dashboard/scripts/resolve-app-dir.sh +164 -0
  51. package/skills/j-dashboard/scripts/snapshot.sh +267 -0
  52. package/skills/j-dashboard-share/SKILL.md +96 -0
  53. package/skills/j-dashboard-share/scripts/upload-snapshot.sh +173 -0
  54. package/skills/j-init/SKILL.md +52 -13
  55. package/skills/j-init/assets/.gitignore_template +1 -2
  56. package/skills/j-init/scripts/apply-scaffold-visibility.sh +192 -0
  57. package/skills/j-init/scripts/init.sh +19 -5
  58. package/skills/j-playbook/SKILL.md +12 -0
  59. package/skills/j-playbook-new/SKILL.md +155 -0
  60. package/skills/j-playbook-new/scripts/playbook-new.sh +332 -0
  61. package/skills/j-publish/scripts/npm_ci_pipeline.sh +6 -0
  62. package/skills/j-skillify/assets/init-new/assets/.gitignore_template +1 -2
  63. package/skills/j-uncharted/SKILL.md +54 -7
  64. package/skills/j-uncharted/assets/NODE_QUESTION_TEMPLATE.md +69 -0
  65. package/skills/j-uncharted/scripts/elicitation-state.sh +45 -7
  66. package/skills/jenga/scripts/load-nl-catalog.js +22 -6
  67. package/skills/jenga/scripts/load-playbooks.sh +146 -35
  68. package/templates/SCRUM_BOARD_SCHEMA.md +18 -6
@@ -0,0 +1,294 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @file project/app/api/scripts/capture-snapshot.js
4
+ *
5
+ * E47_S04_T02 — capture step for `j.dashboard --snapshot`.
6
+ *
7
+ * Calls the dashboard API's `/v1/board`, `/v1/history`, and `/v1/architecture` routes exactly once
8
+ * each and writes their combined JSON to a single artifact, consumable by the bundling/inlining
9
+ * step in `E47_S04_T03` (not yet implemented — this script's job ends at "artifact written to
10
+ * disk").
11
+ *
12
+ * ── Why an ad-hoc, in-process server instead of hitting an already-running one ──────────────────
13
+ * This script always spins up its own short-lived, ephemeral (`--port 0` by default) server
14
+ * instance bound to an explicitly resolved project root, rather than assuming or reaching for some
15
+ * already-running dashboard server. An already-running server on a well-known port (e.g. 3001)
16
+ * could be serving an entirely different project root's data — reusing it would silently defeat
17
+ * the "capture the *invoking* project's data, not this repo's" requirement this task exists to
18
+ * satisfy. A freshly spawned, request-scoped instance removes that ambiguity entirely: whatever
19
+ * root this script resolves is unambiguously the root the three routes below will answer for.
20
+ *
21
+ * ── Reuses E47_S02's generalized data-source resolution — does not re-derive it ─────────────────
22
+ * `../lib/resolve-project-root.js`'s `resolveProjectRoot()` (added by E47_S02_T01, wired into
23
+ * `../server.js` and every parser by E47_S02_T02) is the sole path-resolution mechanism used here:
24
+ * - `--project-root <path>`, if given, is set as the `JENGA_PROJECT_ROOT` env var *before*
25
+ * calling `resolveProjectRoot()` — i.e. it drives E47_S02's own primary override mechanism
26
+ * (the same one `server.js`'s own doc comment names as the future `jenga dashboard start` CLI's
27
+ * intended integration path), rather than inventing a second override convention.
28
+ * - If `--project-root` is not given, `resolveProjectRoot({ cwd: process.cwd() })` is called with
29
+ * no override — exactly mirroring `server.js`'s own no-override behavior (walk up from cwd
30
+ * looking for a `project/board` marker, fail loudly if none is found within the bound).
31
+ * - Either way, the *resolved* (realpath'd) value is then re-pinned onto `JENGA_PROJECT_ROOT`
32
+ * before `../server` is required, so `server.js`'s own load-time check
33
+ * (`if (!process.env.JENGA_PROJECT_ROOT) { ... }`) short-circuits and never re-derives
34
+ * resolution — every parser downstream agrees with exactly what this script already validated.
35
+ * If `resolveProjectRoot()` ever throws (e.g. no `project/board` marker found, or an explicit
36
+ * `--project-root` that doesn't exist), this script fails loudly with that same descriptive error
37
+ * and never starts a server or writes a partial artifact.
38
+ *
39
+ * ── Output artifact shape (the hand-off contract for E47_S04_T03) ────────────────────────────────
40
+ * A single UTF-8 JSON file:
41
+ * {
42
+ * "schema_version": 1,
43
+ * "captured_at": "<ISO 8601 UTC timestamp>",
44
+ * "project_root": "<absolute, realpath'd project root this snapshot was captured against>",
45
+ * "routes": {
46
+ * "board": <full API envelope from GET /v1/board, i.e. { data, meta, error }>,
47
+ * "history": <full API envelope from GET /v1/history, i.e. { data, meta, error }>,
48
+ * "architecture": <full API envelope from GET /v1/architecture, i.e. { data, meta, error }>
49
+ * }
50
+ * }
51
+ * Each `routes.<name>` value is the *full* envelope exactly as the route returned it (see
52
+ * `../response.js`'s `successResponse`/`errorResponse` shape) — deliberately not unwrapped to a
53
+ * bare `.data` — so `E47_S04_T03`'s bundler can decide for itself how to feed this into the UI's
54
+ * existing `client.js` request contract (which itself expects `{ data, meta, error }` and throws on
55
+ * a truthy `error`) without this task guessing that choice on its behalf. Since capture already
56
+ * hard-fails on any route error (see below), `error` will always be `null` in a written artifact —
57
+ * it is kept in the shape anyway so the two representations (a live API response vs. a captured
58
+ * one) stay structurally identical.
59
+ *
60
+ * ── Failure behavior ──────────────────────────────────────────────────────────────────────────
61
+ * Any of the following is treated as a hard failure: the ad-hoc server fails to start, a route
62
+ * request errors at the network level, a route responds with a non-2xx status, a route responds
63
+ * with non-JSON, or a route's own JSON envelope carries a truthy `error` field. In every case: the
64
+ * ad-hoc server is closed, a specific, actionable message is printed to stderr (naming the route
65
+ * and the failure reason), the process exits non-zero, and **no artifact is written** — never a
66
+ * partial or silently-empty snapshot.
67
+ *
68
+ * ── Node compatibility ────────────────────────────────────────────────────────────────────────
69
+ * Uses the built-in `http` module rather than global `fetch`, to stay compatible with the root
70
+ * `package.json`'s declared `engines.node: >=14.13.1` floor (global `fetch` only became available
71
+ * unflagged in Node 18).
72
+ *
73
+ * Usage:
74
+ * node capture-snapshot.js [--project-root <path>] [--out <path>] [--port <n>]
75
+ *
76
+ * --project-root <path> Explicit project root override (see above). Default: resolve by
77
+ * walking up from the current working directory.
78
+ * --out <path> Where to write the combined snapshot JSON. Default:
79
+ * "./dashboard-snapshot-data.json" (relative to cwd). Final on-disk
80
+ * location for a real `--snapshot` run is E47_S04_T03's call, not this
81
+ * script's — it only writes wherever `--out` points.
82
+ * --port <n> Port for the ad-hoc capture server. Default: 0 (OS-assigned ephemeral
83
+ * port) — deliberately not the dashboard's usual default port, so this
84
+ * never collides with (or is confused for) a real already-running server.
85
+ */
86
+
87
+ 'use strict';
88
+
89
+ const path = require('path');
90
+ const http = require('http');
91
+ const fs = require('fs');
92
+
93
+ const ROUTES = ['/v1/board', '/v1/history', '/v1/architecture'];
94
+ const ROUTE_KEYS = {
95
+ '/v1/board': 'board',
96
+ '/v1/history': 'history',
97
+ '/v1/architecture': 'architecture',
98
+ };
99
+
100
+ function printUsage() {
101
+ console.log(`Usage: capture-snapshot.js [--project-root <path>] [--out <path>] [--port <n>]
102
+
103
+ --project-root <path> Explicit project root override, passed through to E47_S02's
104
+ resolveProjectRoot() as the JENGA_PROJECT_ROOT override (the same
105
+ mechanism server.js itself honors). Defaults to walking up from the
106
+ current working directory looking for a project/board marker.
107
+ --out <path> Where to write the combined snapshot JSON.
108
+ Default: ./dashboard-snapshot-data.json (relative to cwd).
109
+ --port <n> Port for the ad-hoc capture server instance. Default: 0
110
+ (OS-assigned ephemeral port).
111
+ `);
112
+ }
113
+
114
+ function die(message) {
115
+ console.error(`Error: capture-snapshot: ${message}`);
116
+ process.exit(1);
117
+ }
118
+
119
+ function parseArgs(argv) {
120
+ const args = { projectRoot: null, out: null, port: 0 };
121
+ for (let i = 0; i < argv.length; i++) {
122
+ const token = argv[i];
123
+ switch (token) {
124
+ case '--project-root':
125
+ args.projectRoot = argv[++i];
126
+ if (!args.projectRoot) die('--project-root requires a value');
127
+ break;
128
+ case '--out':
129
+ args.out = argv[++i];
130
+ if (!args.out) die('--out requires a value');
131
+ break;
132
+ case '--port': {
133
+ const raw = argv[++i];
134
+ const parsed = parseInt(raw, 10);
135
+ if (raw === undefined || isNaN(parsed) || parsed < 0 || parsed > 65535) {
136
+ die(`--port must be a valid port number (0-65535), got: ${raw}`);
137
+ }
138
+ args.port = parsed;
139
+ break;
140
+ }
141
+ case '-h':
142
+ case '--help':
143
+ printUsage();
144
+ process.exit(0);
145
+ break;
146
+ default:
147
+ printUsage();
148
+ die(`unknown argument: ${token}`);
149
+ }
150
+ }
151
+ return args;
152
+ }
153
+
154
+ /**
155
+ * Issue a single GET request to the ad-hoc capture server and parse its JSON envelope. Rejects
156
+ * (rather than resolving with a partial/error payload) on any network error, non-2xx status,
157
+ * non-JSON body, or a truthy `error` field in the parsed envelope — the caller treats a rejection
158
+ * as a hard capture failure.
159
+ */
160
+ function fetchJson(port, routePath) {
161
+ return new Promise((resolve, reject) => {
162
+ const req = http.get(
163
+ { host: '127.0.0.1', port, path: routePath, timeout: 15000 },
164
+ (res) => {
165
+ let body = '';
166
+ res.setEncoding('utf8');
167
+ res.on('data', (chunk) => {
168
+ body += chunk;
169
+ });
170
+ res.on('end', () => {
171
+ let parsed;
172
+ try {
173
+ parsed = JSON.parse(body);
174
+ } catch (err) {
175
+ reject(
176
+ new Error(
177
+ `${routePath} returned a non-JSON response (status ${res.statusCode}): ${err.message}`
178
+ )
179
+ );
180
+ return;
181
+ }
182
+ if (res.statusCode < 200 || res.statusCode >= 300 || (parsed && parsed.error)) {
183
+ const reason =
184
+ parsed && parsed.error
185
+ ? `${parsed.error.code}: ${parsed.error.message}`
186
+ : `HTTP ${res.statusCode}`;
187
+ reject(new Error(`${routePath} returned an error response — ${reason}`));
188
+ return;
189
+ }
190
+ resolve(parsed);
191
+ });
192
+ }
193
+ );
194
+ req.on('timeout', () => {
195
+ req.destroy(new Error(`${routePath} timed out after 15s — is the capture server reachable?`));
196
+ });
197
+ req.on('error', (err) => {
198
+ reject(new Error(`${routePath} request failed: ${err.message} — is the capture server reachable?`));
199
+ });
200
+ });
201
+ }
202
+
203
+ function startServer(app, port) {
204
+ return new Promise((resolve, reject) => {
205
+ const server = app.listen(port, '127.0.0.1');
206
+ server.once('listening', () => resolve(server));
207
+ server.once('error', (err) => {
208
+ reject(new Error(`could not start the ad-hoc capture server on port ${port}: ${err.message}`));
209
+ });
210
+ });
211
+ }
212
+
213
+ async function main() {
214
+ const args = parseArgs(process.argv.slice(2));
215
+
216
+ // eslint-disable-next-line global-require
217
+ const { resolveProjectRoot } = require('../lib/resolve-project-root');
218
+
219
+ if (args.projectRoot) {
220
+ // Drive E47_S02's own primary override mechanism rather than inventing a second one.
221
+ process.env.JENGA_PROJECT_ROOT = args.projectRoot;
222
+ }
223
+
224
+ let resolvedRoot;
225
+ try {
226
+ resolvedRoot = resolveProjectRoot();
227
+ } catch (err) {
228
+ die(err.message);
229
+ return; // unreachable — die() exits — but keeps linters happy about resolvedRoot's usage below
230
+ }
231
+
232
+ // Re-pin the *resolved* (realpath'd) value so server.js's own load-time resolution becomes a
233
+ // no-op and every downstream parser agrees with what was just validated here.
234
+ process.env.JENGA_PROJECT_ROOT = resolvedRoot;
235
+
236
+ const outPath = path.resolve(args.out || 'dashboard-snapshot-data.json');
237
+
238
+ let app;
239
+ try {
240
+ // eslint-disable-next-line global-require
241
+ ({ app } = require('../server'));
242
+ } catch (err) {
243
+ die(`failed to load the dashboard API server: ${err.message}`);
244
+ return;
245
+ }
246
+
247
+ let server;
248
+ try {
249
+ server = await startServer(app, args.port);
250
+ } catch (err) {
251
+ die(err.message);
252
+ return;
253
+ }
254
+
255
+ const boundPort = server.address().port;
256
+
257
+ const routeResults = {};
258
+ try {
259
+ for (const routePath of ROUTES) {
260
+ // Sequential, not parallel: on the first failure we stop immediately with a clear,
261
+ // single-cause error rather than a pile of concurrent rejections to untangle.
262
+ // eslint-disable-next-line no-await-in-loop
263
+ routeResults[ROUTE_KEYS[routePath]] = await fetchJson(boundPort, routePath);
264
+ }
265
+ } catch (err) {
266
+ server.close();
267
+ die(`snapshot capture failed — ${err.message}. No artifact was written.`);
268
+ return;
269
+ }
270
+
271
+ server.close();
272
+
273
+ const snapshot = {
274
+ schema_version: 1,
275
+ captured_at: new Date().toISOString(),
276
+ project_root: resolvedRoot,
277
+ routes: routeResults,
278
+ };
279
+
280
+ try {
281
+ fs.writeFileSync(outPath, `${JSON.stringify(snapshot, null, 2)}\n`);
282
+ } catch (err) {
283
+ die(`failed to write snapshot artifact to ${outPath}: ${err.message}`);
284
+ return;
285
+ }
286
+
287
+ console.log(`Snapshot captured: ${outPath}`);
288
+ console.log(` project_root: ${resolvedRoot}`);
289
+ console.log(` routes: ${Object.keys(routeResults).join(', ')}`);
290
+ }
291
+
292
+ main().catch((err) => {
293
+ die(err && err.stack ? err.stack : String(err));
294
+ });
@@ -0,0 +1,112 @@
1
+ /**
2
+ * @file project/app/api/server.js
3
+ * Jenga AI API server entry point.
4
+ *
5
+ * Usage:
6
+ * node project/app/api/server.js
7
+ * JENGA_API_PORT=4000 node project/app/api/server.js
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ const { resolveProjectRoot } = require('./lib/resolve-project-root');
13
+
14
+ // Pin the resolved project root as an explicit override *before* any router/parser module loads —
15
+ // each parser (board.js, git-log.js, rapports.js, architecture.js, knowledge-graph.js) computes its
16
+ // own root via resolveProjectRoot() at its own module-load time, so this must run first.
17
+ //
18
+ // Deliberately calls resolveProjectRoot() rather than setting a raw `process.cwd()` literal: the
19
+ // real launch paths in this repo (root `npm run dashboard:start`/`api:start`, both of which use
20
+ // `--prefix project/app`) run with `cwd` set to `project/app` by npm, not the repo root — and
21
+ // `project/app` itself has no `project/board` two levels below it (`project/board` is a *sibling*
22
+ // of `project/app`). A raw `cwd` override would incorrectly `throw` in that case. Calling
23
+ // resolveProjectRoot() here performs the same override-else-walk-up resolution the module already
24
+ // does (walk-up from `cwd` correctly finds `project/board` above `project/app`), then pins that
25
+ // *resolved* value into the env var — every parser's own subsequent call becomes a cheap env-var
26
+ // read instead of repeating the walk, and every parser is guaranteed to agree on the same root even
27
+ // if `process.cwd()` changes later in this process's lifetime. If a caller already set an override
28
+ // (e.g. a future `jenga dashboard start` CLI subcommand that knows the user's true invocation
29
+ // directory more reliably than this process's own `cwd`), this is a no-op — resolveProjectRoot()
30
+ // already treats an explicit override as authoritative over any walk-up.
31
+ if (!process.env.JENGA_PROJECT_ROOT) {
32
+ process.env.JENGA_PROJECT_ROOT = resolveProjectRoot();
33
+ }
34
+
35
+ const express = require('express');
36
+ const cors = require('cors');
37
+
38
+ const healthRouter = require('./routes/health');
39
+ const boardRouter = require('./routes/board');
40
+ const historyRouter = require('./routes/history');
41
+ const architectureRouter = require('./routes/architecture');
42
+ const rapportsRouter = require('./routes/rapports');
43
+ const documentationRouter = require('./routes/documentation');
44
+
45
+ const { API_VERSION } = require('./response');
46
+
47
+ const PORT = parseInt(process.env.JENGA_API_PORT || '3001', 10);
48
+
49
+ const app = express();
50
+
51
+ // ── Middleware ─────────────────────────────────────────────────────────────────
52
+ app.use(cors());
53
+ app.use(express.json());
54
+
55
+ // ── Routes ─────────────────────────────────────────────────────────────────────
56
+ app.use('/v1/health', healthRouter);
57
+ app.use('/v1/board', boardRouter);
58
+ app.use('/v1/history', historyRouter);
59
+ app.use('/v1/architecture', architectureRouter);
60
+ app.use('/v1/rapports', rapportsRouter);
61
+ app.use('/v1/documentation', documentationRouter);
62
+
63
+ // ── Fallback routes ────────────────────────────────────────────────────────────
64
+ // Registered on demand (not at require-time) so callers that mount additional
65
+ // routes on `app` after requiring this module — e.g. dashboard-start.cjs
66
+ // serving the built UI — can do so before the catch-all 404 swallows them.
67
+ const { errorResponse } = require('./response');
68
+ const { ERROR_CODES } = require('./types');
69
+
70
+ function attachFallbackRoutes(targetApp, { rootRedirect = true } = {}) {
71
+ if (rootRedirect) {
72
+ targetApp.get('/', (req, res) => res.redirect('/v1/health'));
73
+ }
74
+
75
+ targetApp.use((req, res) => {
76
+ res.status(404).json(errorResponse(ERROR_CODES.NOT_FOUND, `Route '${req.path}' not found`));
77
+ });
78
+ }
79
+
80
+ // ── Start ──────────────────────────────────────────────────────────────────────
81
+ let server;
82
+
83
+ if (require.main === module) {
84
+ attachFallbackRoutes(app);
85
+ server = app.listen(PORT, () => {
86
+ console.log(`[jenga-api] v${API_VERSION} listening on port ${PORT}`);
87
+ });
88
+ registerShutdownHandlers(server);
89
+ }
90
+
91
+ // ── Graceful Shutdown ──────────────────────────────────────────────────────────
92
+ function registerShutdownHandlers(srv) {
93
+ const FORCE_EXIT_MS = 5000;
94
+
95
+ function shutdown(signal) {
96
+ console.log(`[jenga-api] Received ${signal} — shutting down gracefully…`);
97
+ srv.close(() => {
98
+ console.log('[jenga-api] All connections closed. Exiting cleanly.');
99
+ process.exit(0);
100
+ });
101
+
102
+ setTimeout(() => {
103
+ console.error('[jenga-api] Forced exit after 5s timeout.');
104
+ process.exit(1);
105
+ }, FORCE_EXIT_MS).unref();
106
+ }
107
+
108
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
109
+ process.on('SIGINT', () => shutdown('SIGINT'));
110
+ }
111
+
112
+ module.exports = { app, registerShutdownHandlers, attachFallbackRoutes };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @file api/types.js
3
+ * JSDoc type definitions for the Jenga AI API response envelope.
4
+ */
5
+
6
+ /**
7
+ * @typedef {Object} Meta
8
+ * @property {string} timestamp - ISO 8601 UTC timestamp of the response
9
+ * @property {string} version - API version string (e.g. "1.0.0")
10
+ */
11
+
12
+ /**
13
+ * @typedef {Object} ApiError
14
+ * @property {string} code - Screaming-snake-case error code (see ERROR_CODES)
15
+ * @property {string} message - Human-readable description
16
+ * @property {Object} [details] - Optional structured details
17
+ */
18
+
19
+ /**
20
+ * @typedef {Object} ApiEnvelope
21
+ * @template T
22
+ * @property {T|null} data - Resource payload (null on error)
23
+ * @property {Meta} meta - Response metadata
24
+ * @property {ApiError|null} error - Error information (null on success)
25
+ */
26
+
27
+ /**
28
+ * String enum of all supported error codes.
29
+ * @readonly
30
+ * @enum {string}
31
+ */
32
+ const ERROR_CODES = {
33
+ EPIC_NOT_FOUND: 'EPIC_NOT_FOUND',
34
+ PARSE_ERROR: 'PARSE_ERROR',
35
+ INTERNAL_ERROR: 'INTERNAL_ERROR',
36
+ NOT_FOUND: 'NOT_FOUND',
37
+ INVALID_QUERY_PARAM: 'INVALID_QUERY_PARAM',
38
+ };
39
+
40
+ module.exports = { ERROR_CODES };
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "jenga-app",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "workspaces": [
6
+ "api",
7
+ "ui"
8
+ ],
9
+ "dependencies": {
10
+ "express": "^4.18.2"
11
+ },
12
+ "scripts": {
13
+ "install:all": "npm install --workspaces --include-workspace-root",
14
+ "api:start": "node api/server.js",
15
+ "api:dev": "node --watch api/server.js",
16
+ "ui:dev": "npm run dev --workspace=ui",
17
+ "ui:build": "npm run build --workspace=ui",
18
+ "dashboard:start": "node ui/scripts/dashboard-start.cjs",
19
+ "dashboard:open": "node ui/scripts/dashboard-open.cjs"
20
+ }
21
+ }