@nebularstreams/statify 3.0.8 → 3.0.9

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 (3) hide show
  1. package/package.json +2 -2
  2. package/readme.md +28 -0
  3. package/tool/cli.js +53 -3
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nebularstreams/statify",
3
- "version": "3.0.8",
4
- "description": "Generate Cool Landing and Documentation Pages",
3
+ "version": "3.0.9",
4
+ "description": "Agent-friendly Cool Landing Page and Documentation generator",
5
5
  "scripts": {
6
6
  "build:app": "node tool/cli.js app",
7
7
  "pack:check": "npm pack --dry-run"
package/readme.md CHANGED
@@ -28,10 +28,38 @@ statify folder <source> [destination]
28
28
  statify file <file> [destination] <source>
29
29
  statify list <list-file> <source> [destination] [filter-id]
30
30
  statify app [simple|software|worlds]
31
+ statify skill install [--force]
31
32
  ```
32
33
 
33
34
  Run `statify --help` for the same reference at the command line.
34
35
 
36
+ ### Install the Codex skill
37
+
38
+ Install the packaged website-authoring skill directly from npm:
39
+
40
+ ```sh
41
+ npx @nebularstreams/statify@3.0.9 skill install
42
+ ```
43
+
44
+ Or install it from a project-local Statify dependency without downloading a
45
+ different version:
46
+
47
+ ```sh
48
+ npx --no-install statify skill install
49
+ ```
50
+
51
+ The command copies the skill into
52
+ `$CODEX_HOME/skills/statify-site`, or `~/.codex/skills/statify-site` when
53
+ `CODEX_HOME` is not set. It refuses to replace an existing installation by
54
+ default. To deliberately update it:
55
+
56
+ ```sh
57
+ npx @nebularstreams/statify@3.0.9 skill install --force
58
+ ```
59
+
60
+ Restart or refresh Codex after installation, then invoke the skill as
61
+ `$statify-site`.
62
+
35
63
  ### Initialize a website
36
64
 
37
65
  ```sh
package/tool/cli.js CHANGED
@@ -3,12 +3,13 @@
3
3
  "use strict";
4
4
 
5
5
  const fs = require("node:fs");
6
+ const os = require("node:os");
6
7
  const path = require("node:path");
7
8
  const { spawnSync } = require("node:child_process");
8
9
  const publish = require("../src/publisher-lib");
9
10
 
10
11
  const PACKAGE_ROOT = path.resolve(__dirname, "..");
11
- const COMMANDS = new Set(["init", "app", "list", "folder", "file"]);
12
+ const COMMANDS = new Set(["init", "app", "list", "folder", "file", "skill"]);
12
13
 
13
14
  function fail(message, code = 1) {
14
15
  const error = new Error(message);
@@ -22,7 +23,8 @@ function usage() {
22
23
  statify folder <source> [destination]
23
24
  statify file <file> [destination] <source>
24
25
  statify list <list-file> <source> [destination] [filter-id]
25
- statify app [simple|software|worlds]`;
26
+ statify app [simple|software|worlds]
27
+ statify skill install [--force]`;
26
28
  }
27
29
 
28
30
  function existingDirectory(value, label) {
@@ -162,6 +164,54 @@ function app(application = "simple") {
162
164
  if (result.status !== 0) fail(`Application build failed with exit code ${result.status}`, result.status || 1);
163
165
  }
164
166
 
167
+ function installSkill(options) {
168
+ const unknown = options.filter((option) => option !== "--force");
169
+ if (unknown.length) fail(`Unknown skill install option: ${unknown[0]}`);
170
+
171
+ const
172
+ force = options.includes("--force"),
173
+ source = path.join(PACKAGE_ROOT, "skill", "statify-site"),
174
+ codexHome = process.env.CODEX_HOME
175
+ ? path.resolve(process.env.CODEX_HOME)
176
+ : path.join(os.homedir(), ".codex"),
177
+ skillsDirectory = path.join(codexHome, "skills"),
178
+ target = path.join(skillsDirectory, "statify-site");
179
+
180
+ if (!fs.existsSync(path.join(source, "SKILL.md"))) {
181
+ fail(`Packaged skill is missing: ${source}`);
182
+ }
183
+ if (fs.existsSync(target) && !force) {
184
+ fail(`Skill is already installed at ${target}\nRun again with --force to replace it.`);
185
+ }
186
+
187
+ fs.mkdirSync(skillsDirectory, { recursive: true });
188
+ const temporary = path.join(skillsDirectory, `.statify-site-install-${process.pid}-${Date.now()}`);
189
+ fs.cpSync(source, temporary, { recursive: true, errorOnExist: true });
190
+
191
+ if (!fs.existsSync(target)) {
192
+ fs.renameSync(temporary, target);
193
+ } else {
194
+ const backup = path.join(skillsDirectory, `.statify-site-backup-${process.pid}-${Date.now()}`);
195
+ fs.renameSync(target, backup);
196
+ try {
197
+ fs.renameSync(temporary, target);
198
+ fs.rmSync(backup, { recursive: true, force: true });
199
+ } catch (error) {
200
+ if (fs.existsSync(temporary)) fs.rmSync(temporary, { recursive: true, force: true });
201
+ if (!fs.existsSync(target)) fs.renameSync(backup, target);
202
+ throw error;
203
+ }
204
+ }
205
+
206
+ console.log(`Installed statify-site skill in ${target}`);
207
+ console.log("Restart or refresh Codex, then invoke it with $statify-site.");
208
+ }
209
+
210
+ function skill(action, ...options) {
211
+ if (action !== "install") fail("Usage: statify skill install [--force]");
212
+ installSkill(options);
213
+ }
214
+
165
215
  function invocation(argv) {
166
216
  if (COMMANDS.has(argv[0])) return [argv[0], argv.slice(1)];
167
217
  fail(`Unknown command: ${argv[0]}\n\n${usage()}`);
@@ -174,7 +224,7 @@ async function main(argv) {
174
224
  }
175
225
 
176
226
  const [command, args] = invocation(argv);
177
- await { init, folder, file, list, app }[command](...args);
227
+ await { init, folder, file, list, app, skill }[command](...args);
178
228
  }
179
229
 
180
230
  main(process.argv.slice(2)).catch((error) => {