@grainulation/grainulation 1.0.1 → 1.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.
package/lib/server.mjs CHANGED
@@ -12,16 +12,7 @@
12
12
  */
13
13
 
14
14
  import { execSync } from 'node:child_process';
15
- import {
16
- existsSync,
17
- mkdirSync,
18
- readdirSync,
19
- readFileSync,
20
- renameSync,
21
- statSync,
22
- watchFile,
23
- writeFileSync,
24
- } from 'node:fs';
15
+ import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, statSync, writeFileSync } from 'node:fs';
25
16
  import { createServer } from 'node:http';
26
17
  import { createRequire } from 'node:module';
27
18
  import { dirname, extname, join, resolve } from 'node:path';
@@ -186,7 +177,7 @@ function detectTool(pkg) {
186
177
  // 1. Global npm
187
178
  try {
188
179
  const out = execSync(`npm list -g ${pkg} --depth=0 2>/dev/null`, { stdio: 'pipe', encoding: 'utf-8' });
189
- const match = out.match(new RegExp(escapeRegex(pkg) + '@(\\S+)'));
180
+ const match = out.match(new RegExp(`${escapeRegex(pkg)}@(\\S+)`));
190
181
  if (match) return { installed: true, version: match[1], method: 'global' };
191
182
  } catch {
192
183
  /* not found */
@@ -261,7 +252,7 @@ function runDoctor() {
261
252
  // Environment checks
262
253
  checks.push({
263
254
  name: 'Node.js',
264
- status: parseInt(nodeVersion.slice(1)) >= 18 ? 'pass' : 'warning',
255
+ status: parseInt(nodeVersion.slice(1), 10) >= 18 ? 'pass' : 'warning',
265
256
  detail: nodeVersion,
266
257
  category: 'environment',
267
258
  });
@@ -334,16 +325,15 @@ function scaffold(targetDir, options = {}) {
334
325
  mkdirSync(dir, { recursive: true });
335
326
 
336
327
  // claims.json (atomic write-then-rename)
337
- const claimsData =
338
- JSON.stringify(
339
- {
340
- claims: [],
341
- meta: { created: new Date().toISOString(), tool: 'grainulation' },
342
- },
343
- null,
344
- 2,
345
- ) + '\n';
346
- const tmpClaims = join(dir, 'claims.json.tmp.' + process.pid);
328
+ const claimsData = `${JSON.stringify(
329
+ {
330
+ claims: [],
331
+ meta: { created: new Date().toISOString(), tool: 'grainulation' },
332
+ },
333
+ null,
334
+ 2,
335
+ )}\n`;
336
+ const tmpClaims = join(dir, `claims.json.tmp.${process.pid}`);
347
337
  writeFileSync(tmpClaims, claimsData);
348
338
  renameSync(tmpClaims, join(dir, 'claims.json'));
349
339
 
@@ -356,16 +346,15 @@ function scaffold(targetDir, options = {}) {
356
346
 
357
347
  // orchard.json (if multi-sprint, atomic write-then-rename)
358
348
  if (options.includeOrchard) {
359
- const orchardData =
360
- JSON.stringify(
361
- {
362
- sprints: [],
363
- settings: { sync_interval: 'manual' },
364
- },
365
- null,
366
- 2,
367
- ) + '\n';
368
- const tmpOrchard = join(dir, 'orchard.json.tmp.' + process.pid);
349
+ const orchardData = `${JSON.stringify(
350
+ {
351
+ sprints: [],
352
+ settings: { sync_interval: 'manual' },
353
+ },
354
+ null,
355
+ 2,
356
+ )}\n`;
357
+ const tmpOrchard = join(dir, `orchard.json.tmp.${process.pid}`);
369
358
  writeFileSync(tmpOrchard, orchardData);
370
359
  renameSync(tmpOrchard, join(dir, 'orchard.json'));
371
360
  }
@@ -443,7 +432,7 @@ table{width:100%;border-collapse:collapse}th,td{padding:8px 12px;border-bottom:1
443
432
  th{color:#9ca3af}code{background:#1e293b;padding:2px 6px;border-radius:4px;font-size:13px}</style></head>
444
433
  <body><h1>grainulation API</h1><p>${ROUTES.length} endpoints</p>
445
434
  <table><tr><th>Method</th><th>Path</th><th>Description</th></tr>
446
- ${ROUTES.map((r) => '<tr><td><code>' + r.method + '</code></td><td><code>' + r.path + '</code></td><td>' + r.description + '</td></tr>').join('')}
435
+ ${ROUTES.map((r) => `<tr><td><code>${r.method}</code></td><td><code>${r.path}</code></td><td>${r.description}</td></tr>`).join('')}
447
436
  </table></body></html>`;
448
437
  res.writeHead(200, { 'Content-Type': 'text/html' });
449
438
  res.end(html);
@@ -588,7 +577,7 @@ ${ROUTES.map((r) => '<tr><td><code>' + r.method + '</code></td><td><code>' + r.p
588
577
 
589
578
  // ── Static files ──
590
579
  const filePath = url.pathname === '/' ? '/index.html' : url.pathname;
591
- const resolved = resolve(PUBLIC_DIR, '.' + filePath);
580
+ const resolved = resolve(PUBLIC_DIR, `.${filePath}`);
592
581
 
593
582
  if (!resolved.startsWith(PUBLIC_DIR)) {
594
583
  res.writeHead(403);
package/lib/setup.js CHANGED
@@ -1,7 +1,7 @@
1
- const readline = require("node:readline");
2
- const { execSync } = require("node:child_process");
3
- const { getInstallable, getCategories } = require("./ecosystem");
4
- const { getVersion } = require("./doctor");
1
+ const readline = require('node:readline');
2
+ const { execSync } = require('node:child_process');
3
+ const { getInstallable, getCategories } = require('./ecosystem');
4
+ const { getVersion } = require('./doctor');
5
5
 
6
6
  /**
7
7
  * Interactive setup wizard.
@@ -12,24 +12,24 @@ const { getVersion } = require("./doctor");
12
12
 
13
13
  const ROLES = [
14
14
  {
15
- name: "Researcher",
16
- description: "Run research sprints, grow evidence, write briefs",
17
- tools: ["wheat"],
15
+ name: 'Researcher',
16
+ description: 'Run research sprints, grow evidence, write briefs',
17
+ tools: ['wheat'],
18
18
  },
19
19
  {
20
- name: "Researcher + Dashboard",
21
- description: "Research sprints with real-time permission dashboard",
22
- tools: ["wheat", "farmer"],
20
+ name: 'Researcher + Dashboard',
21
+ description: 'Research sprints with real-time permission dashboard',
22
+ tools: ['wheat', 'farmer'],
23
23
  },
24
24
  {
25
- name: "Team Lead",
26
- description: "Coordinate multiple sprints, review analytics",
27
- tools: ["wheat", "farmer", "orchard", "harvest"],
25
+ name: 'Team Lead',
26
+ description: 'Coordinate multiple sprints, review analytics',
27
+ tools: ['wheat', 'farmer', 'orchard', 'harvest'],
28
28
  },
29
29
  {
30
- name: "Full Ecosystem",
31
- description: "Everything. All 7 tools.",
32
- tools: ["wheat", "farmer", "barn", "mill", "silo", "harvest", "orchard"],
30
+ name: 'Full Ecosystem',
31
+ description: 'Everything. All 7 tools.',
32
+ tools: ['wheat', 'farmer', 'barn', 'mill', 'silo', 'harvest', 'orchard'],
33
33
  },
34
34
  ];
35
35
 
@@ -45,24 +45,24 @@ async function run() {
45
45
  output: process.stdout,
46
46
  });
47
47
 
48
- console.log("");
49
- console.log(" \x1b[1;33mgrainulation setup\x1b[0m");
50
- console.log(" What are you trying to do?");
51
- console.log("");
48
+ console.log('');
49
+ console.log(' \x1b[1;33mgrainulation setup\x1b[0m');
50
+ console.log(' What are you trying to do?');
51
+ console.log('');
52
52
 
53
53
  for (let i = 0; i < ROLES.length; i++) {
54
54
  const role = ROLES[i];
55
55
  console.log(` \x1b[1m${i + 1}.\x1b[0m ${role.name}`);
56
56
  console.log(` \x1b[2m${role.description}\x1b[0m`);
57
- console.log(` Tools: ${role.tools.join(", ")}`);
58
- console.log("");
57
+ console.log(` Tools: ${role.tools.join(', ')}`);
58
+ console.log('');
59
59
  }
60
60
 
61
- const answer = await ask(rl, " Choose (1-4): ");
61
+ const answer = await ask(rl, ' Choose (1-4): ');
62
62
  const choice = parseInt(answer, 10);
63
63
 
64
- if (choice < 1 || choice > ROLES.length || isNaN(choice)) {
65
- console.log("\n \x1b[31mInvalid choice.\x1b[0m\n");
64
+ if (choice < 1 || choice > ROLES.length || Number.isNaN(choice)) {
65
+ console.log('\n \x1b[31mInvalid choice.\x1b[0m\n');
66
66
  rl.close();
67
67
  return;
68
68
  }
@@ -70,9 +70,9 @@ async function run() {
70
70
  const role = ROLES[choice - 1];
71
71
  const toInstall = [];
72
72
 
73
- console.log("");
73
+ console.log('');
74
74
  console.log(` \x1b[1mSetting up: ${role.name}\x1b[0m`);
75
- console.log("");
75
+ console.log('');
76
76
 
77
77
  for (const toolName of role.tools) {
78
78
  const tool = getInstallable().find((t) => t.name === toolName);
@@ -80,9 +80,7 @@ async function run() {
80
80
 
81
81
  const version = getVersion(tool.package);
82
82
  if (version) {
83
- console.log(
84
- ` \x1b[32m\u2713\x1b[0m ${tool.name} already installed (${version})`,
85
- );
83
+ console.log(` \x1b[32m\u2713\x1b[0m ${tool.name} already installed (${version})`);
86
84
  } else {
87
85
  toInstall.push(tool);
88
86
  console.log(` \x1b[33m+\x1b[0m ${tool.name} will be installed`);
@@ -90,44 +88,37 @@ async function run() {
90
88
  }
91
89
 
92
90
  if (toInstall.length === 0) {
93
- console.log("");
94
- console.log(" \x1b[32mEverything is already installed.\x1b[0m");
95
- console.log(
96
- " Run \x1b[1mnpx @grainulation/wheat init\x1b[0m to start a research sprint.",
97
- );
91
+ console.log('');
92
+ console.log(' \x1b[32mEverything is already installed.\x1b[0m');
93
+ console.log(' Run \x1b[1mnpx @grainulation/wheat init\x1b[0m to start a research sprint.');
98
94
  rl.close();
99
95
  return;
100
96
  }
101
97
 
102
- console.log("");
103
- const confirm = await ask(
104
- rl,
105
- ` Install ${toInstall.length} package(s)? (y/N): `,
106
- );
98
+ console.log('');
99
+ const confirm = await ask(rl, ` Install ${toInstall.length} package(s)? (y/N): `);
107
100
 
108
- if (confirm.toLowerCase() !== "y") {
109
- console.log("\n \x1b[2mAborted.\x1b[0m\n");
101
+ if (confirm.toLowerCase() !== 'y') {
102
+ console.log('\n \x1b[2mAborted.\x1b[0m\n');
110
103
  rl.close();
111
104
  return;
112
105
  }
113
106
 
114
- console.log("");
107
+ console.log('');
115
108
  for (const tool of toInstall) {
116
109
  console.log(` Installing ${tool.package}...`);
117
110
  try {
118
- execSync(`npm install -g ${tool.package}`, { stdio: "pipe" });
111
+ execSync(`npm install -g ${tool.package}`, { stdio: 'pipe' });
119
112
  console.log(` \x1b[32m\u2713\x1b[0m ${tool.name} installed`);
120
113
  } catch (err) {
121
- console.log(
122
- ` \x1b[31m\u2717\x1b[0m ${tool.name} failed: ${err.message}`,
123
- );
114
+ console.log(` \x1b[31m\u2717\x1b[0m ${tool.name} failed: ${err.message}`);
124
115
  }
125
116
  }
126
117
 
127
- console.log("");
128
- console.log(" \x1b[32mSetup complete.\x1b[0m");
129
- console.log(" Start with: npx @grainulation/wheat init");
130
- console.log("");
118
+ console.log('');
119
+ console.log(' \x1b[32mSetup complete.\x1b[0m');
120
+ console.log(' Start with: npx @grainulation/wheat init');
121
+ console.log('');
131
122
  rl.close();
132
123
  }
133
124
 
package/package.json CHANGED
@@ -1,9 +1,8 @@
1
1
  {
2
2
  "name": "@grainulation/grainulation",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "Structured research for decisions that satisfice",
5
5
  "license": "MIT",
6
- "type": "module",
7
6
  "workspaces": [
8
7
  "packages/*"
9
8
  ],
package/public/index.html CHANGED
@@ -440,7 +440,7 @@ body {
440
440
  </main>
441
441
  </div>
442
442
  <footer class="footer">
443
- <span>grainulation v1.0.0 -- @grainulation/grainulation</span>
443
+ <span>grainulation v1.0.2 -- @grainulation/grainulation</span>
444
444
  <div class="footer-links">
445
445
  <a href="http://localhost:9091">wheat</a>
446
446
  <a href="http://localhost:9090">farmer</a>