hotsheet 0.8.0 → 0.9.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.
Files changed (2) hide show
  1. package/dist/cli.js +27 -21
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -552,7 +552,7 @@ var init_channel_config = __esm({
552
552
  // src/cli.ts
553
553
  import { mkdirSync as mkdirSync6 } from "fs";
554
554
  import { tmpdir } from "os";
555
- import { join as join12, resolve as resolve3 } from "path";
555
+ import { join as join12, resolve as resolve4 } from "path";
556
556
 
557
557
  // src/backup.ts
558
558
  init_connection();
@@ -2394,7 +2394,7 @@ import { fileURLToPath as fileURLToPath2 } from "url";
2394
2394
  // src/routes/api.ts
2395
2395
  import { existsSync as existsSync7, mkdirSync as mkdirSync4, rmSync as rmSync5 } from "fs";
2396
2396
  import { Hono } from "hono";
2397
- import { basename, extname, join as join9, relative as relative2 } from "path";
2397
+ import { basename, extname, join as join9, relative as relative2, resolve as resolve3 } from "path";
2398
2398
 
2399
2399
  // src/skills.ts
2400
2400
  init_file_settings();
@@ -2886,8 +2886,8 @@ function notifyChange() {
2886
2886
  changeVersion++;
2887
2887
  const waiters = pollWaiters;
2888
2888
  pollWaiters = [];
2889
- for (const resolve4 of waiters) {
2890
- resolve4(changeVersion);
2889
+ for (const resolve5 of waiters) {
2890
+ resolve5(changeVersion);
2891
2891
  }
2892
2892
  }
2893
2893
  apiRoutes.get("/poll", async (c) => {
@@ -2896,11 +2896,11 @@ apiRoutes.get("/poll", async (c) => {
2896
2896
  return c.json({ version: changeVersion });
2897
2897
  }
2898
2898
  const version = await Promise.race([
2899
- new Promise((resolve4) => {
2900
- pollWaiters.push(resolve4);
2899
+ new Promise((resolve5) => {
2900
+ pollWaiters.push(resolve5);
2901
2901
  }),
2902
- new Promise((resolve4) => {
2903
- setTimeout(() => resolve4(changeVersion), 3e4);
2902
+ new Promise((resolve5) => {
2903
+ setTimeout(() => resolve5(changeVersion), 3e4);
2904
2904
  })
2905
2905
  ]);
2906
2906
  return c.json({ version });
@@ -3140,7 +3140,11 @@ apiRoutes.post("/attachments/:id/reveal", async (c) => {
3140
3140
  apiRoutes.get("/attachments/file/*", async (c) => {
3141
3141
  const filePath = c.req.path.replace("/api/attachments/file/", "");
3142
3142
  const dataDir2 = c.get("dataDir");
3143
- const fullPath = join9(dataDir2, "attachments", filePath);
3143
+ const attachDir = resolve3(join9(dataDir2, "attachments"));
3144
+ const fullPath = resolve3(join9(attachDir, filePath));
3145
+ if (!fullPath.startsWith(attachDir + "/") && fullPath !== attachDir) {
3146
+ return c.json({ error: "Invalid path" }, 403);
3147
+ }
3144
3148
  if (!existsSync7(fullPath)) {
3145
3149
  return c.json({ error: "File not found" }, 404);
3146
3150
  }
@@ -3213,7 +3217,8 @@ apiRoutes.patch("/settings", async (c) => {
3213
3217
  apiRoutes.get("/file-settings", async (c) => {
3214
3218
  const { readFileSettings: readFileSettings2 } = await Promise.resolve().then(() => (init_file_settings(), file_settings_exports));
3215
3219
  const dataDir2 = c.get("dataDir");
3216
- return c.json(readFileSettings2(dataDir2));
3220
+ const { secret, secretPathHash, port: port2, ...safe } = readFileSettings2(dataDir2);
3221
+ return c.json(safe);
3217
3222
  });
3218
3223
  apiRoutes.patch("/file-settings", async (c) => {
3219
3224
  const { writeFileSettings: writeFileSettings2 } = await Promise.resolve().then(() => (init_file_settings(), file_settings_exports));
@@ -4072,10 +4077,10 @@ pageRoutes.get("/", (c) => {
4072
4077
 
4073
4078
  // src/server.ts
4074
4079
  function tryServe(fetch2, port2) {
4075
- return new Promise((resolve4, reject) => {
4080
+ return new Promise((resolve5, reject) => {
4076
4081
  const server = serve({ fetch: fetch2, port: port2 });
4077
4082
  server.on("listening", () => {
4078
- resolve4(port2);
4083
+ resolve5(port2);
4079
4084
  });
4080
4085
  server.on("error", (err) => {
4081
4086
  reject(err);
@@ -4127,8 +4132,9 @@ async function startServer(port2, dataDir2, options) {
4127
4132
  } else if (isMutation) {
4128
4133
  const origin = c.req.header("Origin");
4129
4134
  const referer = c.req.header("Referer");
4130
- const isBrowser = !!(origin || referer);
4131
- if (!isBrowser) {
4135
+ const localhostPattern = /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?(\/|$)/;
4136
+ const isSameOrigin = origin && localhostPattern.test(origin) || referer && localhostPattern.test(referer);
4137
+ if (!isSameOrigin) {
4132
4138
  return c.json({
4133
4139
  error: "Missing X-Hotsheet-Secret header. Read .hotsheet/settings.json for the correct port and secret.",
4134
4140
  recovery: "Re-read .hotsheet/settings.json to get the correct port and secret, and re-read your skill files for updated instructions."
@@ -4213,10 +4219,10 @@ function isFirstUseToday() {
4213
4219
  return last !== today;
4214
4220
  }
4215
4221
  function fetchLatestVersion() {
4216
- return new Promise((resolve4) => {
4222
+ return new Promise((resolve5) => {
4217
4223
  const req = get(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`, { timeout: 5e3 }, (res) => {
4218
4224
  if (res.statusCode !== 200) {
4219
- resolve4(null);
4225
+ resolve5(null);
4220
4226
  return;
4221
4227
  }
4222
4228
  let data = "";
@@ -4225,18 +4231,18 @@ function fetchLatestVersion() {
4225
4231
  });
4226
4232
  res.on("end", () => {
4227
4233
  try {
4228
- resolve4(JSON.parse(data).version);
4234
+ resolve5(JSON.parse(data).version);
4229
4235
  } catch {
4230
- resolve4(null);
4236
+ resolve5(null);
4231
4237
  }
4232
4238
  });
4233
4239
  });
4234
4240
  req.on("error", () => {
4235
- resolve4(null);
4241
+ resolve5(null);
4236
4242
  });
4237
4243
  req.on("timeout", () => {
4238
4244
  req.destroy();
4239
- resolve4(null);
4245
+ resolve5(null);
4240
4246
  });
4241
4247
  });
4242
4248
  }
@@ -4338,7 +4344,7 @@ function parseArgs(argv) {
4338
4344
  }
4339
4345
  break;
4340
4346
  case "--data-dir":
4341
- dataDir2 = resolve3(args[++i]);
4347
+ dataDir2 = resolve4(args[++i]);
4342
4348
  break;
4343
4349
  case "--check-for-updates":
4344
4350
  forceUpdateCheck = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hotsheet",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "A lightweight local project management tool. Create, categorize, and prioritize tickets with a fast bullet-list interface, then export an Up Next worklist for AI tools.",
5
5
  "type": "module",
6
6
  "license": "MIT",