frogoe 0.3.0 → 0.3.2

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 (2) hide show
  1. package/dist/cli.js +68 -28
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -119,13 +119,18 @@ node_modules/
119
119
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
120
120
  import path from "path";
121
121
  import { fileURLToPath } from "url";
122
- var here, CONTRACT_SOURCE, scaffold, registryRoot;
122
+ var here, contractSourceFor, CONTRACT_SOURCE, scaffold, registryRootFor, registryRoot;
123
123
  var init_init = __esm({
124
124
  "src/init.ts"() {
125
125
  "use strict";
126
126
  init_templates();
127
127
  here = path.dirname(fileURLToPath(import.meta.url));
128
- CONTRACT_SOURCE = existsSync(path.join(here, "../../contract/src/contract.js")) ? path.join(here, "../../contract/src/contract.js") : path.join(here, "../contract/contract.js");
128
+ contractSourceFor = (base) => {
129
+ const repo = path.join(base, "../../contract/src/contract.js");
130
+ if (existsSync(repo)) return repo;
131
+ return path.join(base, "contract/contract.js");
132
+ };
133
+ CONTRACT_SOURCE = contractSourceFor(here);
129
134
  scaffold = (name, options) => {
130
135
  const root = options?.dir ?? process.cwd();
131
136
  const target = path.resolve(root, name);
@@ -161,12 +166,12 @@ var init_init = __esm({
161
166
  }
162
167
  return { dir: target, files: files.map(([rel]) => rel) };
163
168
  };
164
- registryRoot = () => {
169
+ registryRootFor = (base) => {
165
170
  const candidates = [
166
- path.resolve(here, "../../../registry"),
171
+ path.resolve(base, "../../../registry"),
167
172
  // repo source mode
168
- path.resolve(here, "../registry")
169
- // dist mode (build:copy)
173
+ path.resolve(base, "registry")
174
+ // dist mode: beside the bundle
170
175
  ];
171
176
  for (const candidate of candidates) {
172
177
  if (existsSync(path.join(candidate, "registry.json"))) {
@@ -174,28 +179,28 @@ var init_init = __esm({
174
179
  }
175
180
  }
176
181
  throw new Error(
177
- "frogoe: registry not found (expected ../registry or packaged copy). Run from the repo or install @frogoe/cli fully."
182
+ "frogoe: registry not found (expected the repo registry or the packaged copy beside the CLI). Run from the repo or reinstall frogoe."
178
183
  );
179
184
  };
185
+ registryRoot = () => registryRootFor(here);
180
186
  }
181
187
  });
182
188
 
183
189
  // src/add.ts
184
190
  import { cpSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
185
191
  import path2 from "path";
186
- var STYLE_PATTERN, MARKUP_PATTERN, parseBlock, blockMarker, injectIntoHtml, addBlock;
192
+ var parseBlock, blockMarker, injectIntoHtml, addBlock;
187
193
  var init_add = __esm({
188
194
  "src/add.ts"() {
189
195
  "use strict";
190
196
  init_init();
191
- STYLE_PATTERN = /<style>([\s\S]*?)<\/style>/u;
192
- MARKUP_PATTERN = /<\/style>\s*([\s\S]*)$/u;
193
197
  parseBlock = (source) => {
194
- const styleMatch = STYLE_PATTERN.exec(source);
195
- const markupMatch = MARKUP_PATTERN.exec(source);
198
+ const styleOpen = source.indexOf("<style>");
199
+ const styleClose = source.indexOf("</style>");
200
+ const css = styleOpen === -1 || styleClose === -1 || styleClose < styleOpen ? null : source.slice(styleOpen + "<style>".length, styleClose);
196
201
  return {
197
- css: styleMatch?.[1]?.trim() ?? null,
198
- markup: (markupMatch?.[1] ?? "").trim()
202
+ css: css?.trim() ?? null,
203
+ markup: (styleClose === -1 ? "" : source.slice(styleClose + "</style>".length)).trim()
199
204
  };
200
205
  };
201
206
  blockMarker = (name) => `<!-- frogoe:block:${name} -->`;
@@ -723,11 +728,32 @@ var init_bundle2 = __esm({
723
728
  });
724
729
 
725
730
  // ../lint/src/brief.ts
726
- var stripComment, parseBrief;
731
+ var KEY_PATTERN, WS, stripComment, parseLine, parseBrief;
727
732
  var init_brief = __esm({
728
733
  "../lint/src/brief.ts"() {
729
734
  "use strict";
730
- stripComment = (value) => value.replace(/\s+#.*$/u, "").trim().replace(/^["']|["']$/gu, "");
735
+ KEY_PATTERN = /^[a-z-]+$/u;
736
+ WS = /\s/u;
737
+ stripComment = (value) => {
738
+ let cut = -1;
739
+ for (let i = 1; i < value.length; i += 1) {
740
+ if (value[i] === "#" && WS.test(value[i - 1] ?? "")) {
741
+ cut = i;
742
+ break;
743
+ }
744
+ }
745
+ return (cut === -1 ? value : value.slice(0, cut)).trim().replace(/^["']|["']$/gu, "");
746
+ };
747
+ parseLine = (line) => {
748
+ let indent = 0;
749
+ while (indent < line.length && line[indent] === " ") indent += 1;
750
+ const body = line.slice(indent);
751
+ const colon = body.indexOf(":");
752
+ if (colon === -1) return null;
753
+ const key = body.slice(0, colon);
754
+ if (!KEY_PATTERN.test(key)) return null;
755
+ return { indent, key, rest: body.slice(colon + 1) };
756
+ };
731
757
  parseBrief = (source) => {
732
758
  const match = /^---\r?\n([\s\S]*?)\r?\n---/u.exec(source);
733
759
  if (!match) {
@@ -739,20 +765,20 @@ var init_brief = __esm({
739
765
  if (rawLine.trim() === "") {
740
766
  continue;
741
767
  }
742
- const nested = /^\s{2,}([a-z-]+):\s*(.*)$/u.exec(rawLine);
743
- const top = /^([a-z-]+):\s*(.*)$/u.exec(rawLine);
744
- if (nested && section === "palette") {
745
- const key = nested[1];
746
- brief[key] = stripComment(nested[2] ?? "");
768
+ const parsed = parseLine(rawLine);
769
+ if (!parsed) {
747
770
  continue;
748
771
  }
749
- if (top) {
750
- section = top[1] ?? "";
772
+ if (parsed.indent >= 2 && section === "palette") {
773
+ brief[parsed.key] = stripComment(parsed.rest);
774
+ continue;
775
+ }
776
+ if (parsed.indent === 0) {
777
+ section = parsed.key;
751
778
  if (section === "palette") {
752
779
  continue;
753
780
  }
754
- const key = section;
755
- brief[key] = stripComment(top[2] ?? "");
781
+ brief[parsed.key] = stripComment(parsed.rest);
756
782
  }
757
783
  }
758
784
  return brief;
@@ -2799,12 +2825,21 @@ import { existsSync as existsSync6, mkdirSync as mkdirSync6, chmodSync, writeFil
2799
2825
  import os3 from "os";
2800
2826
  import path9 from "path";
2801
2827
  import { gunzipSync } from "zlib";
2802
- var URL_PATTERN, parseTunnelUrl, octalAt, extractSingleFile, ENV_PIN, assetName, binaryFileName, cacheBase, resolveLatestTag, mb, downloadWithProgress, binaryEchoes, resolveBinary, startTunnel;
2828
+ var URL_PATTERN, parseTunnelUrl, TAG_PATTERN, assertSafeTag, octalAt, extractSingleFile, ENV_PIN, assetName, binaryFileName, cacheBase, resolveLatestTag, mb, downloadWithProgress, binaryEchoes, resolveBinary, startTunnel;
2803
2829
  var init_tunnel = __esm({
2804
2830
  "src/net/tunnel.ts"() {
2805
2831
  "use strict";
2806
2832
  URL_PATTERN = /https:\/\/[a-z0-9-]+\.trycloudflare\.com/iu;
2807
2833
  parseTunnelUrl = (chunk) => URL_PATTERN.exec(chunk)?.[0];
2834
+ TAG_PATTERN = /^\d{4}\.\d+\.\d+(-[A-Za-z0-9.]+)?$/u;
2835
+ assertSafeTag = (tag) => {
2836
+ if (!TAG_PATTERN.test(tag)) {
2837
+ throw new Error(
2838
+ `cloudflared version "${tag}" is not a valid release tag (expected e.g. 2025.10.1)`
2839
+ );
2840
+ }
2841
+ return tag;
2842
+ };
2808
2843
  octalAt = (block, offset, length) => {
2809
2844
  const raw = block.subarray(offset, offset + length).toString("utf-8");
2810
2845
  const digits = raw.replace(/[\0 ]/gu, "");
@@ -2897,10 +2932,15 @@ var init_tunnel = __esm({
2897
2932
  `cloudflared publishes no build for ${platform}/${process.arch} \u2014 install it and put \`cloudflared\` on PATH`
2898
2933
  );
2899
2934
  }
2900
- const tag = process.env[ENV_PIN] ?? await resolveLatestTag();
2935
+ const tag = process.env[ENV_PIN] ? assertSafeTag(process.env[ENV_PIN]) : assertSafeTag(await resolveLatestTag());
2901
2936
  const root = path9.join(cacheBase(platform, process.env, os3.homedir()), "frogoe", "cloudflared");
2902
2937
  const dir = path9.join(root, tag);
2903
2938
  const bin = path9.join(dir, binaryFileName(platform));
2939
+ const rootResolved = path9.resolve(root);
2940
+ const binResolved = path9.resolve(bin);
2941
+ if (!binResolved.startsWith(rootResolved + path9.sep)) {
2942
+ throw new Error("cloudflared binary path escaped the frogoe cache \u2014 refusing to execute");
2943
+ }
2904
2944
  if (existsSync6(bin) && binaryEchoes(bin, tag)) return { downloaded: false, path: bin };
2905
2945
  onProgress?.(`downloading cloudflared ${tag} (~25 MB, once)\u2026`);
2906
2946
  const res = await fetch(
@@ -3601,7 +3641,7 @@ import { defineCommand as defineCommand9, runMain } from "citty";
3601
3641
  // package.json
3602
3642
  var package_default = {
3603
3643
  name: "frogoe",
3604
- version: "0.3.0",
3644
+ version: "0.3.2",
3605
3645
  description: "froge CLI \u2014 the agent's hands: init, add, run, check, bundle",
3606
3646
  homepage: "https://github.com/frogoe/engine#readme",
3607
3647
  bugs: "https://github.com/frogoe/engine/issues",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frogoe",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "froge CLI — the agent's hands: init, add, run, check, bundle",
5
5
  "homepage": "https://github.com/frogoe/engine#readme",
6
6
  "bugs": "https://github.com/frogoe/engine/issues",