hotsheet 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.
Files changed (2) hide show
  1. package/dist/cli.js +131 -14
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -72,9 +72,9 @@ var init_gitignore = __esm({
72
72
  });
73
73
 
74
74
  // src/cli.ts
75
- import { mkdirSync as mkdirSync3 } from "fs";
75
+ import { mkdirSync as mkdirSync4 } from "fs";
76
76
  import { tmpdir } from "os";
77
- import { join as join6, resolve } from "path";
77
+ import { join as join7, resolve } from "path";
78
78
 
79
79
  // src/cleanup.ts
80
80
  import { rmSync as rmSync2 } from "fs";
@@ -1475,8 +1475,8 @@ apiRoutes.post("/tickets/:id/attachments", async (c) => {
1475
1475
  mkdirSync2(attachDir, { recursive: true });
1476
1476
  const storedPath = join4(attachDir, storedName);
1477
1477
  const buffer = Buffer.from(await file.arrayBuffer());
1478
- const { writeFileSync: writeFileSync3 } = await import("fs");
1479
- writeFileSync3(storedPath, buffer);
1478
+ const { writeFileSync: writeFileSync4 } = await import("fs");
1479
+ writeFileSync4(storedPath, buffer);
1480
1480
  const attachment = await addAttachment(id, originalName, storedPath);
1481
1481
  scheduleAllSync();
1482
1482
  notifyChange();
@@ -1501,8 +1501,8 @@ apiRoutes.get("/attachments/file/*", async (c) => {
1501
1501
  if (!existsSync2(fullPath)) {
1502
1502
  return c.json({ error: "File not found" }, 404);
1503
1503
  }
1504
- const { readFileSync: readFileSync3 } = await import("fs");
1505
- const content = readFileSync3(fullPath);
1504
+ const { readFileSync: readFileSync4 } = await import("fs");
1505
+ const content = readFileSync4(fullPath);
1506
1506
  const ext = extname(fullPath).toLowerCase();
1507
1507
  const mimeTypes = {
1508
1508
  ".png": "image/png",
@@ -1955,6 +1955,117 @@ async function startServer(port, dataDir2) {
1955
1955
  exec(`${openCmd} ${url}`);
1956
1956
  }
1957
1957
 
1958
+ // src/update-check.ts
1959
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
1960
+ import { get } from "https";
1961
+ import { homedir } from "os";
1962
+ import { dirname as dirname2, join as join6 } from "path";
1963
+ import { fileURLToPath as fileURLToPath2 } from "url";
1964
+ var DATA_DIR = join6(homedir(), ".hotsheet");
1965
+ var CHECK_FILE = join6(DATA_DIR, "last-update-check");
1966
+ var PACKAGE_NAME = "hotsheet";
1967
+ function getCurrentVersion() {
1968
+ try {
1969
+ const dir = dirname2(fileURLToPath2(import.meta.url));
1970
+ const pkg = JSON.parse(readFileSync3(join6(dir, "..", "package.json"), "utf-8"));
1971
+ return pkg.version;
1972
+ } catch {
1973
+ return "0.0.0";
1974
+ }
1975
+ }
1976
+ function getLastCheckDate() {
1977
+ try {
1978
+ if (existsSync4(CHECK_FILE)) {
1979
+ return readFileSync3(CHECK_FILE, "utf-8").trim();
1980
+ }
1981
+ } catch {
1982
+ }
1983
+ return null;
1984
+ }
1985
+ function saveCheckDate() {
1986
+ mkdirSync3(DATA_DIR, { recursive: true });
1987
+ writeFileSync3(CHECK_FILE, (/* @__PURE__ */ new Date()).toISOString().slice(0, 10), "utf-8");
1988
+ }
1989
+ function isFirstUseToday() {
1990
+ const last = getLastCheckDate();
1991
+ if (last === null) return true;
1992
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
1993
+ return last !== today;
1994
+ }
1995
+ function fetchLatestVersion() {
1996
+ return new Promise((resolve2) => {
1997
+ const req = get(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`, { timeout: 5e3 }, (res) => {
1998
+ if (res.statusCode !== 200) {
1999
+ resolve2(null);
2000
+ return;
2001
+ }
2002
+ let data = "";
2003
+ res.on("data", (chunk) => {
2004
+ data += chunk.toString();
2005
+ });
2006
+ res.on("end", () => {
2007
+ try {
2008
+ resolve2(JSON.parse(data).version);
2009
+ } catch {
2010
+ resolve2(null);
2011
+ }
2012
+ });
2013
+ });
2014
+ req.on("error", () => {
2015
+ resolve2(null);
2016
+ });
2017
+ req.on("timeout", () => {
2018
+ req.destroy();
2019
+ resolve2(null);
2020
+ });
2021
+ });
2022
+ }
2023
+ function detectUpgradeCommand() {
2024
+ const binPath = process.argv[1] || "";
2025
+ if (binPath.includes("/.bun/") || binPath.includes("/bun/")) {
2026
+ return `bun update -g ${PACKAGE_NAME}`;
2027
+ }
2028
+ if (binPath.includes("/.pnpm/") || binPath.includes("/pnpm/")) {
2029
+ return `pnpm update -g ${PACKAGE_NAME}`;
2030
+ }
2031
+ if (binPath.includes("/.yarn/") || binPath.includes("/yarn/")) {
2032
+ return `yarn global upgrade ${PACKAGE_NAME}`;
2033
+ }
2034
+ return `npm update -g ${PACKAGE_NAME}`;
2035
+ }
2036
+ function compareVersions(current, latest) {
2037
+ const a = current.split(".").map(Number);
2038
+ const b = latest.split(".").map(Number);
2039
+ for (let i = 0; i < 3; i++) {
2040
+ if ((a[i] || 0) < (b[i] || 0)) return -1;
2041
+ if ((a[i] || 0) > (b[i] || 0)) return 1;
2042
+ }
2043
+ return 0;
2044
+ }
2045
+ async function checkForUpdates(force) {
2046
+ if (!force && !isFirstUseToday()) return;
2047
+ const current = getCurrentVersion();
2048
+ const latest = await fetchLatestVersion();
2049
+ saveCheckDate();
2050
+ if (latest === null || compareVersions(current, latest) >= 0) return;
2051
+ const cmd = detectUpgradeCommand();
2052
+ const updateLine = `Update available: ${current} \u2192 ${latest}`;
2053
+ const cmdLine = `Run: ${cmd}`;
2054
+ const width = Math.max(updateLine.length, cmdLine.length) + 4;
2055
+ const pad = (text, visLen) => text + " ".repeat(Math.max(0, width - visLen));
2056
+ const border = "\u2500".repeat(width);
2057
+ const empty = " ".repeat(width);
2058
+ console.log("");
2059
+ console.log(` \u250C${border}\u2510`);
2060
+ console.log(` \u2502${empty}\u2502`);
2061
+ console.log(` \u2502 ${pad(`Update available: ${current} \u2192 \x1B[32m${latest}\x1B[0m`, updateLine.length + 2)}\u2502`);
2062
+ console.log(` \u2502${empty}\u2502`);
2063
+ console.log(` \u2502 ${pad(`Run: \x1B[36m${cmd}\x1B[0m`, cmdLine.length + 2)}\u2502`);
2064
+ console.log(` \u2502${empty}\u2502`);
2065
+ console.log(` \u2514${border}\u2518`);
2066
+ console.log("");
2067
+ }
2068
+
1958
2069
  // src/cli.ts
1959
2070
  function printUsage() {
1960
2071
  console.log(`
@@ -1964,9 +2075,10 @@ Usage:
1964
2075
  hotsheet [options]
1965
2076
 
1966
2077
  Options:
1967
- --port <number> Port to run on (default: 4174)
1968
- --data-dir <path> Store data in an alternative location (default: .hotsheet/)
1969
- --help Show this help message
2078
+ --port <number> Port to run on (default: 4174)
2079
+ --data-dir <path> Store data in an alternative location (default: .hotsheet/)
2080
+ --check-for-updates Check for new versions now
2081
+ --help Show this help message
1970
2082
 
1971
2083
  Examples:
1972
2084
  hotsheet
@@ -1977,8 +2089,9 @@ Examples:
1977
2089
  function parseArgs(argv) {
1978
2090
  const args = argv.slice(2);
1979
2091
  let port = 4174;
1980
- let dataDir2 = join6(process.cwd(), ".hotsheet");
2092
+ let dataDir2 = join7(process.cwd(), ".hotsheet");
1981
2093
  let demo = null;
2094
+ let forceUpdateCheck = false;
1982
2095
  for (let i = 0; i < args.length; i++) {
1983
2096
  const arg = args[i];
1984
2097
  if (arg.startsWith("--demo:")) {
@@ -2005,13 +2118,16 @@ function parseArgs(argv) {
2005
2118
  case "--data-dir":
2006
2119
  dataDir2 = resolve(args[++i]);
2007
2120
  break;
2121
+ case "--check-for-updates":
2122
+ forceUpdateCheck = true;
2123
+ break;
2008
2124
  default:
2009
2125
  console.error(`Unknown option: ${arg}`);
2010
2126
  printUsage();
2011
2127
  process.exit(1);
2012
2128
  }
2013
2129
  }
2014
- return { port, dataDir: dataDir2, demo };
2130
+ return { port, dataDir: dataDir2, demo, forceUpdateCheck };
2015
2131
  }
2016
2132
  async function main() {
2017
2133
  const parsed = parseArgs(process.argv);
@@ -2019,8 +2135,9 @@ async function main() {
2019
2135
  printUsage();
2020
2136
  process.exit(1);
2021
2137
  }
2022
- const { port, demo } = parsed;
2138
+ const { port, demo, forceUpdateCheck } = parsed;
2023
2139
  let { dataDir: dataDir2 } = parsed;
2140
+ await checkForUpdates(forceUpdateCheck);
2024
2141
  if (demo !== null) {
2025
2142
  const scenario = DEMO_SCENARIOS.find((s) => s.id === demo);
2026
2143
  if (!scenario) {
@@ -2031,12 +2148,12 @@ async function main() {
2031
2148
  }
2032
2149
  process.exit(1);
2033
2150
  }
2034
- dataDir2 = join6(tmpdir(), `hotsheet-demo-${demo}-${Date.now()}`);
2151
+ dataDir2 = join7(tmpdir(), `hotsheet-demo-${demo}-${Date.now()}`);
2035
2152
  console.log(`
2036
2153
  DEMO MODE: ${scenario.label}
2037
2154
  `);
2038
2155
  }
2039
- mkdirSync3(dataDir2, { recursive: true });
2156
+ mkdirSync4(dataDir2, { recursive: true });
2040
2157
  if (demo === null) {
2041
2158
  ensureGitignore(process.cwd());
2042
2159
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hotsheet",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
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",