genesis-compiler 1.10.2 → 1.10.4

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/docs/templates.md CHANGED
@@ -1,10 +1,20 @@
1
1
  # Project opening and templates
2
2
 
3
- The official JSKIT choices are **Basic app**, **Database app**, and **Accounts
4
- app**. Basic keeps the existing `jskit/public` ID and `public` branch. Database
5
- uses `jskit/database` and the `database` branch, adding MySQL without login.
6
- Accounts keeps `jskit/accounts` and the `accounts` branch. These are complete
7
- starter projects with ready tests; importing source still runs no setup commands.
3
+ The official JSKIT choices are **Basic app**, **App with no users, but a database**,
4
+ **App with users** and **Accounts hub**. Basic keeps the existing `jskit/public` ID and
5
+ `public` branch. Database uses `jskit/database` and the `database` branch,
6
+ adding MySQL without login. Accounts keeps `jskit/accounts` and the `accounts`
7
+ branch. Accounts hub uses `jskit/accounts-hub` and the `accounts-hub` branch:
8
+ an OpenID Connect hub that gives an owner's other apps one sign-in. These are
9
+ complete starter projects with ready tests; importing source still runs no
10
+ setup commands.
11
+
12
+ Each framework component also has one official **Basic app**: `django/basic`,
13
+ `rails/basic`, `spring-boot/basic`, `express/basic` and `nextjs/basic`. Each is
14
+ the `basic` branch of its `vibe64-dev/seed-<technology>` repository and stores
15
+ notes from one form: SQLite for Django, Rails, Express and Next.js, and
16
+ MySQL/MariaDB for Spring Boot. Only the Rails starter has sign-in, with a seeded
17
+ development account. The catalogue lists JSKIT first, then the frameworks.
8
18
 
9
19
  `genesis init` installs the portable Genesis documents, workflow skills, and
10
20
  agent integration in an ordinary Git repository. It preserves existing source.
@@ -66,8 +76,10 @@ genesis templates apply official:jskit/public
66
76
 
67
77
  The first-party JSKIT repository is
68
78
  the [JSKIT seed repository](https://github.com/vibe64-dev/seed-jskit). `public` supplies
69
- an adaptive public app; `accounts` adds local accounts, private Home and MySQL.
70
- Each branch is a complete, current Genesis project with actual application
79
+ an adaptive public app; `accounts` adds local accounts, private Home and MySQL;
80
+ `accounts-hub` is an OpenID Connect hub for one sign-in across apps.
81
+ The framework starters live in `seed-django`, `seed-rails`, `seed-spring-boot`,
82
+ `seed-express` and `seed-nextjs`, each on its `basic` branch. Each branch is a complete, current Genesis project with actual application
71
83
  source, dependency lockfile, setup/run contracts and focused checks.
72
84
 
73
85
  Applying fetches the explicitly named branch once, resolves its commit and reads
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genesis-compiler",
3
- "version": "1.10.2",
3
+ "version": "1.10.4",
4
4
  "type": "module",
5
5
  "description": "An agent-independent prompt, multi-language code-index, cleanup, and verification companion with project agent guidance.",
6
6
  "repository": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genesis",
3
- "version": "1.10.2",
3
+ "version": "1.10.4",
4
4
  "description": "Makes Codex aware of optional Genesis adoption for existing projects.",
5
5
  "author": {
6
6
  "name": "Mobily Enterprises"
@@ -1,5 +1,5 @@
1
1
  import { AsyncLocalStorage } from 'node:async_hooks';
2
- import { access, mkdir, mkdtemp, readFile, readdir, rename, rm, writeFile } from 'node:fs/promises';
2
+ import { access, chmod, mkdir, mkdtemp, readFile, readdir, rename, rm, stat, writeFile } from 'node:fs/promises';
3
3
  import { createRequire } from 'node:module';
4
4
  import os from 'node:os';
5
5
  import path from 'node:path';
@@ -137,6 +137,10 @@ async function installParser(definition, root, { signal, onProgress, environment
137
137
  }
138
138
  }
139
139
  await verifyParser(definition, installation, signal);
140
+ // mkdtemp stages privately (0700); a shared parser root (for example one
141
+ // prepared by root for service users) needs the mode an ordinary directory
142
+ // beside it would have, or other users cannot load the parser.
143
+ await chmod(staging, (await stat(path.dirname(destination))).mode & 0o7777);
140
144
  try {
141
145
  await rename(staging, destination);
142
146
  } catch (error) {
@@ -311,11 +311,20 @@ async function generateStartPrompt({
311
311
  };
312
312
  }
313
313
  let blueprint;
314
+ let uninitializedNew = false;
314
315
  try {
315
316
  blueprint = await readBlueprint(root, { required: true });
316
317
  } catch (error) {
317
318
  if (error?.code !== 'BLUEPRINT_REQUIRED') throw error;
318
- if (await classifyProjectKind({ projectRoot: root }) === 'new') throw error;
319
+ if (await classifyProjectKind({ projectRoot: root }) === 'new') {
320
+ // An empty repository that was never initialized still opens a new-project
321
+ // conversation; the agent initializes Genesis before writing intent.
322
+ if (inspection.projectFormat?.status !== 'uninitialized') throw error;
323
+ uninitializedNew = true;
324
+ blueprint = { path: 'genesis/blueprint.md', description: null };
325
+ }
326
+ }
327
+ if (!blueprint) {
319
328
  return {
320
329
  status: 'ready',
321
330
  task: 'start',
@@ -336,7 +345,10 @@ async function generateStartPrompt({
336
345
  verificationCommands: [],
337
346
  };
338
347
  }
339
- const stack = await readStack(root, { stackPackages });
348
+ // Initialization writes the Stack; until then the selection is empty.
349
+ const stack = uninitializedNew
350
+ ? { components: [], stackPackages: [], guidance: '' }
351
+ : await readStack(root, { stackPackages });
340
352
  const projectKind = await classifyProjectKind({
341
353
  projectRoot: root,
342
354
  stackComponents: stack.components,
@@ -351,7 +363,9 @@ async function generateStartPrompt({
351
363
  .then((profiles) => profiles.map(({ id, name, description }) => ({ id, name, description })))
352
364
  : Promise.resolve([]),
353
365
  inspectProjectSkills({ projectRoot: root, stack }),
354
- startInstructions(instructions, projectKind),
366
+ startInstructions(instructions, projectKind).then((text) => (uninitializedNew
367
+ ? `${text}\n\nGenesis is not initialized in this repository yet. Before writing the Blueprint\nor selecting Stack components, run the Genesis \`init\` operation. Applying a\nready-made template initializes the project itself.`
368
+ : text)),
355
369
  ]);
356
370
  return {
357
371
  status: 'ready',
@@ -367,6 +381,7 @@ async function generateStartPrompt({
367
381
  path: blueprint.path,
368
382
  description: blueprint.description,
369
383
  },
384
+ ...(uninitializedNew ? { genesis: { initialized: false } } : {}),
370
385
  ...sessionPrompt.context,
371
386
  stack: startStackContext(stack),
372
387
  ...(projectKind === 'new'
@@ -11,19 +11,25 @@ export function missingStackResources({ environment = process.env, resources = [
11
11
  throw new TypeError('Stack resource inspection requires an environment object and resource declarations.');
12
12
  }
13
13
  return resources.flatMap(({ component, resource }) => {
14
- const satisfied = resource.environmentAlternatives.some(({ bindings, allowEmpty }) => (
15
- Object.entries(bindings).every(([semantic, name]) => (
16
- present(environment, name, allowEmpty.includes(semantic))
17
- ))
14
+ const missing = resource.environmentAlternatives.map(({ bindings, allowEmpty }) => (
15
+ Object.entries(bindings)
16
+ .filter(([semantic, name]) => !present(environment, name, allowEmpty.includes(semantic)))
17
+ .map(([, name]) => name)
18
18
  ));
19
- if (satisfied) return [];
19
+ if (missing.some((names) => names.length === 0)) return [];
20
20
  const alternatives = resource.environmentAlternatives.map(({ bindings }) => (
21
21
  Object.values(bindings).join(' + ')
22
22
  ));
23
+ // Name what is still absent: defaults may already supply most bindings.
24
+ const described = alternatives.map((alternative, index) => (
25
+ missing[index].length < alternative.split(' + ').length
26
+ ? `${alternative} (missing ${missing[index].join(', ')})`
27
+ : alternative
28
+ ));
23
29
  return [{
24
30
  code: 'STACK_RESOURCE_MISSING',
25
- message: `Stack component ${component} requires ${resource.id}: ${alternatives.join(' OR ')}.`,
26
- details: { component, resource: resource.id, alternatives },
31
+ message: `Stack component ${component} requires ${resource.id}: ${described.join(' OR ')}.`,
32
+ details: { component, resource: resource.id, alternatives, missing },
27
33
  }];
28
34
  });
29
35
  }