rowork 0.1.0 → 0.1.1

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/README.md CHANGED
@@ -7,12 +7,12 @@ toolchain, runs it, generates code and keeps your architecture coherent.
7
7
 
8
8
  > ## ⚠️ This is only the very beginning
9
9
  >
10
- > Rowork is at **version 0.0.1**. The goal is big: a real **meta-framework for Roblox**, from the first
10
+ > Rowork is at **version 0.1.0**. The goal is big: a real **meta-framework for Roblox**, from the first
11
11
  > line of a project to a live game. **What exists today is a small first step towards it**, and most of the
12
12
  > vision is not built yet.
13
13
  >
14
14
  > - **Expect missing features, bugs and breaking changes** without warning.
15
- > - **It is not on npm yet**, and it has been tried on very few games.
15
+ > - **It has been tried on very few games so far**, and it is version 0.1.0.
16
16
  > - **Do not build a serious game on it yet.** Come and look, try it, and tell us what is wrong.
17
17
  >
18
18
  > The [roadmap](docs/roadmap.md) says what exists and what is missing, without promises.
@@ -57,13 +57,13 @@ editable files, and you can drop down to the bare tools at any time.
57
57
 
58
58
  ## Quick start
59
59
 
60
- Rowork is not on npm yet, so install it from the repository:
61
-
62
60
  ```bash
63
- git clone https://github.com/nokogoat/Rowork
64
- cd Rowork && npm install && npm run build && npm link
61
+ npm install -g rowork
65
62
  ```
66
63
 
64
+ Building it from the repository instead (for development or contributing) is documented under
65
+ [Contributing](docs/contributing.md).
66
+
67
67
  Then:
68
68
 
69
69
  ```bash
@@ -1,11 +1,22 @@
1
1
  import { createHash } from "node:crypto";
2
2
  const HEADERS = { "User-Agent": "rowork" };
3
+ /**
4
+ * `api.github.com` allows 60 anonymous requests per hour, shared by every anonymous
5
+ * caller behind the same address — including every GitHub Actions runner in the world.
6
+ * A token (GitHub Actions gives every job one for free, no setup needed) raises that to
7
+ * 1,000 per hour, scoped to this run alone. Never required: without one, Rowork just
8
+ * falls back to the anonymous limit, same as always.
9
+ */
10
+ function authHeader() {
11
+ const token = process.env["GITHUB_TOKEN"] ?? process.env["GH_TOKEN"];
12
+ return token === undefined || token === "" ? {} : { Authorization: `Bearer ${token}` };
13
+ }
3
14
  /** Fetches a release of `owner/repo`: the latest one, or the one tagged `tag`. */
4
15
  export async function getRelease(repository, tag) {
5
16
  const path = tag === undefined ? "latest" : `tags/${tag}`;
6
17
  const url = `https://api.github.com/repos/${repository}/releases/${path}`;
7
18
  // A stalled connection must not hang the CLI: the API answers in well under a second.
8
- const response = await fetch(url, { headers: HEADERS, signal: AbortSignal.timeout(20_000) });
19
+ const response = await fetch(url, { headers: { ...HEADERS, ...authHeader() }, signal: AbortSignal.timeout(20_000) });
9
20
  if (!response.ok)
10
21
  throw new Error(`${url} answered ${response.status}`);
11
22
  return (await response.json());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rowork",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "The meta-framework CLI for Roblox game development. Orchestrates Rojo, roblox-ts and Flamework, and scaffolds your game architecture.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,2 +0,0 @@
1
- export declare const makeToolCommand: import("../plugins/api.js").CommandDefinition;
2
- //# sourceMappingURL=make-tool.d.ts.map
@@ -1,124 +0,0 @@
1
- import { join } from "node:path";
2
- import { RoworkError } from "../cli/errors.js";
3
- import { resolveProjectPath } from "../core/config.js";
4
- import { ensureFlameworkPath, generateFile, importPath, toClassBase, writeToolRegistry, } from "../core/generate.js";
5
- import { defineCommand } from "../plugins/api.js";
6
- import { answered, prompts } from "../ui/prompt.js";
7
- import { nameOrAsk, requireProject } from "./make.js";
8
- function parseCooldown(value) {
9
- const number = Number(value.replace(",", "."));
10
- return value.trim() !== "" && Number.isFinite(number) && number >= 0 && number <= 3600
11
- ? number
12
- : undefined;
13
- }
14
- async function askSettings() {
15
- const cooldown = answered(await prompts.text({
16
- message: "Seconds to wait between two uses?",
17
- placeholder: "0.5",
18
- defaultValue: "0.5",
19
- validate: (value) => parseCooldown(value || "0.5") === undefined ? "A number between 0 and 3600." : undefined,
20
- }));
21
- const canBeDropped = answered(await prompts.confirm({ message: "Can the player drop it on the ground?", initialValue: false }));
22
- const giveOnSpawn = answered(await prompts.confirm({
23
- message: "Give it to every player when they spawn?",
24
- initialValue: true,
25
- }));
26
- return { cooldown: parseCooldown(cooldown || "0.5") ?? 0.5, canBeDropped, giveOnSpawn };
27
- }
28
- function settingsFromOptions(context) {
29
- const raw = context.options["cooldown"];
30
- const cooldown = typeof raw === "string" ? parseCooldown(raw) : 0.5;
31
- if (cooldown === undefined) {
32
- throw new RoworkError(`\`${String(raw)}\` is not a valid cooldown.`, {
33
- hint: "Use a number of seconds between 0 and 3600, e.g. --cooldown 0.5",
34
- });
35
- }
36
- return {
37
- cooldown,
38
- canBeDropped: context.options["droppable"] === true,
39
- giveOnSpawn: context.options["giveOnSpawn"] !== false,
40
- };
41
- }
42
- export const makeToolCommand = defineCommand({
43
- name: "make:tool",
44
- guided: true,
45
- description: "Create a tool players hold: settings, behaviour, and automatic delivery.",
46
- arguments: [
47
- {
48
- name: "name",
49
- description: "name of the tool, e.g. Pickaxe (omit it for the guided version)",
50
- required: false,
51
- },
52
- ],
53
- options: [
54
- { flags: "--cooldown <seconds>", description: "seconds between two uses (default 0.5)" },
55
- { flags: "--droppable", description: "the player can drop it" },
56
- { flags: "--no-give-on-spawn", description: "do not give it to players automatically" },
57
- { flags: "-f, --force", description: "overwrite the tool's own files if they exist" },
58
- ],
59
- async run(context) {
60
- const { root, config } = requireProject(context, "make:tool");
61
- const { name, guided } = await nameOrAsk(context, "make:tool", "What is the tool called?", "Pickaxe");
62
- const settings = guided ? await askSettings() : settingsFromOptions(context);
63
- // `Pickaxe` and `PickaxeTool` both mean the same tool.
64
- const base = toClassBase(name).replace(/(?<=.)Tool$/, "");
65
- const constName = `${base}Tool`;
66
- const force = context.options["force"] === true;
67
- const sharedDirectory = `${config.paths.shared}/tools`;
68
- const componentsDirectory = `${config.paths.source}/server/components`;
69
- const servicesDirectory = config.paths.services;
70
- const created = [];
71
- const write = (directory, fileName, template, variables, own) => {
72
- const written = generateFile({
73
- projectRoot: root,
74
- directory,
75
- fileName,
76
- template,
77
- variables,
78
- force: own && force,
79
- ifExists: own ? "fail" : "skip",
80
- });
81
- if (written !== undefined)
82
- created.push(written);
83
- };
84
- // Shared files first, created once and never overwritten: a failure on
85
- // the tool's own files then leaves nothing harmful behind.
86
- write(sharedDirectory, "ToolDefinition.ts", "tool-definition", {}, false);
87
- write(servicesDirectory, "ToolService.ts", "tool-service", {
88
- definitionImport: importPath(root, servicesDirectory, `${sharedDirectory}/ToolDefinition`),
89
- registryImport: importPath(root, servicesDirectory, `${sharedDirectory}/index`),
90
- }, false);
91
- write(sharedDirectory, `${constName}.ts`, "tool-config", {
92
- constName,
93
- base,
94
- tag: constName,
95
- cooldown: String(settings.cooldown),
96
- canBeDropped: String(settings.canBeDropped),
97
- giveOnSpawn: String(settings.giveOnSpawn),
98
- }, true);
99
- write(componentsDirectory, `${constName}Component.ts`, "tool-component", {
100
- constName,
101
- base,
102
- tag: constName,
103
- className: `${constName}Component`,
104
- configImport: importPath(root, componentsDirectory, `${sharedDirectory}/${constName}`),
105
- }, true);
106
- writeToolRegistry(root, sharedDirectory);
107
- const runtime = resolveProjectPath(root, join(config.paths.source, "server", "runtime.server.ts"));
108
- for (const directory of [servicesDirectory, componentsDirectory]) {
109
- if (ensureFlameworkPath(runtime, directory, context.logger)) {
110
- context.logger.step(`registered ${directory} in runtime.server.ts`);
111
- }
112
- }
113
- for (const file of created)
114
- context.logger.step(file);
115
- context.logger.success(`Created tool ${base}`);
116
- context.logger.blank();
117
- context.logger.info(settings.giveOnSpawn
118
- ? `Every player gets the ${base} when they spawn.`
119
- : `The ${base} is not given automatically: settings are in ${sharedDirectory}/${constName}.ts.`);
120
- context.logger.info(`Write what it does in ${componentsDirectory}/${constName}Component.ts (activate).`);
121
- context.logger.info(`Change its settings later in ${sharedDirectory}/${constName}.ts.`);
122
- },
123
- });
124
- //# sourceMappingURL=make-tool.js.map