@invoicer/cli 1.2.5 → 1.3.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.
package/dist/cli.js CHANGED
@@ -11,6 +11,7 @@ import { registerClientsCommand } from "./commands/clients.js";
11
11
  import { registerTimesheetCommand } from "./commands/timesheet.js";
12
12
  import { registerSenderCommand } from "./commands/sender.js";
13
13
  import { registerDraftsCommand } from "./commands/drafts.js";
14
+ import { registerWorkspaceCommand } from "./commands/workspace.js";
14
15
  function getPackageVersion() {
15
16
  try {
16
17
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -33,6 +34,7 @@ export function createProgram(paths = createProjectPaths()) {
33
34
  registerTimesheetCommand(program, paths);
34
35
  registerSenderCommand(program, paths);
35
36
  registerDraftsCommand(program, paths);
37
+ registerWorkspaceCommand(program, paths);
36
38
  return program;
37
39
  }
38
40
  export async function runCli(argv = process.argv, paths = createProjectPaths()) {
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import { getCustomDataPath, setCustomDataPath, clearCustomDataPath, loadCliSettings, } from "../core/settings.js";
2
+ export function registerWorkspaceCommand(program, paths) {
3
+ program
4
+ .command("workspace")
5
+ .alias("path")
6
+ .description("Manage CLI data path location")
7
+ .option("--list", "Show current workspace path", false)
8
+ .option("--set <path>", "Set custom data path")
9
+ .option("--clear", "Clear custom data path and use default", false)
10
+ .action(async (options) => {
11
+ // If no option provided, show status
12
+ if (!options.list && !options.set && !options.clear) {
13
+ showWorkspaceStatus(paths);
14
+ process.exit(0);
15
+ }
16
+ if (options.list) {
17
+ showWorkspaceStatus(paths);
18
+ process.exit(0);
19
+ }
20
+ if (options.set) {
21
+ try {
22
+ setCustomDataPath(options.set);
23
+ console.log(`\nāœ… Data path set to: ${options.set}`);
24
+ console.log(`\nšŸ“ Data files location:\n ${options.set}/config.json\n ${options.set}/data/timesheet.json\n ${options.set}/data/archive.json\n`);
25
+ process.exit(0);
26
+ }
27
+ catch (error) {
28
+ const message = error instanceof Error ? error.message : String(error);
29
+ console.error(`āŒ Failed to set data path: ${message}`);
30
+ process.exit(1);
31
+ }
32
+ }
33
+ if (options.clear) {
34
+ clearCustomDataPath();
35
+ console.log("\nāœ… Custom data path cleared.");
36
+ console.log(" CLI will now use default location.");
37
+ showWorkspaceStatus(paths);
38
+ process.exit(0);
39
+ }
40
+ });
41
+ }
42
+ function showWorkspaceStatus(paths) {
43
+ const customPath = getCustomDataPath();
44
+ const settings = loadCliSettings();
45
+ console.log("\nšŸ“ Current Workspace Configuration:\n");
46
+ if (customPath) {
47
+ console.log(` Status: āœ… Custom path set`);
48
+ console.log(` Path: ${customPath}`);
49
+ console.log(` Config: ${customPath}/config.json`);
50
+ console.log(` Data: ${customPath}/data/\n`);
51
+ }
52
+ else {
53
+ console.log(` Status: Using default location`);
54
+ console.log(` Path: ${paths.projectRoot}`);
55
+ console.log(` Config: ${paths.configPath}`);
56
+ console.log(` Data: ${paths.timesheetPath.replace("/timesheet.json", "")}/\n`);
57
+ }
58
+ console.log("šŸ“ Usage:\n");
59
+ console.log(" Set custom path: invoicer workspace --set /path/to/workspace");
60
+ console.log(" Clear custom path: invoicer workspace --clear");
61
+ console.log(" Show status: invoicer workspace --list\n");
62
+ }
63
+ //# sourceMappingURL=workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/commands/workspace.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAQ7B,MAAM,UAAU,wBAAwB,CAAC,OAAgB,EAAE,KAAmB;IAC5E,OAAO;SACJ,OAAO,CAAC,WAAW,CAAC;SACpB,KAAK,CAAC,MAAM,CAAC;SACb,WAAW,CAAC,+BAA+B,CAAC;SAC5C,MAAM,CAAC,QAAQ,EAAE,6BAA6B,EAAE,KAAK,CAAC;SACtD,MAAM,CAAC,cAAc,EAAE,sBAAsB,CAAC;SAC9C,MAAM,CAAC,SAAS,EAAE,wCAAwC,EAAE,KAAK,CAAC;SAClE,MAAM,CAAC,KAAK,EAAE,OAAyB,EAAE,EAAE;QAC1C,qCAAqC;QACrC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACpD,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;YAChB,IAAI,CAAC;gBACH,iBAAiB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAC/B,OAAO,CAAC,GAAG,CAAC,yBAAyB,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;gBACpD,OAAO,CAAC,GAAG,CACT,iCAAiC,OAAO,CAAC,GAAG,oBAAoB,OAAO,CAAC,GAAG,4BAA4B,OAAO,CAAC,GAAG,sBAAsB,CACzI,CAAC;gBACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACvE,OAAO,CAAC,KAAK,CAAC,8BAA8B,OAAO,EAAE,CAAC,CAAC;gBACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QAED,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAClB,mBAAmB,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;YAC7C,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;YACrD,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAmB;IAC9C,MAAM,UAAU,GAAG,iBAAiB,EAAE,CAAC;IACvC,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IAEnC,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;IAEvD,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,aAAa,UAAU,EAAE,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,aAAa,UAAU,cAAc,CAAC,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC,aAAa,UAAU,UAAU,CAAC,CAAC;IACjD,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;QAC9C,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;QAC7C,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;IACpF,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC3B,OAAO,CAAC,GAAG,CAAC,iEAAiE,CAAC,CAAC;IAC/E,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;IAC/D,OAAO,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC;AAClE,CAAC"}
@@ -1,7 +1,8 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
- import { homedir } from "node:os";
4
+ import { homedir, platform } from "node:os";
5
+ import { getCustomDataPath } from "./settings.js";
5
6
  export function findProjectRoot(startDir = process.cwd()) {
6
7
  let currentDir = startDir;
7
8
  const root = path.parse(currentDir).root;
@@ -18,12 +19,29 @@ export function createProjectPaths(startDir = process.cwd()) {
18
19
  const moduleRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
19
20
  const foundRoot = findProjectRoot(startDir);
20
21
  const hasModuleConfig = fs.existsSync(path.join(moduleRoot, "config.json"));
21
- // Priority: 1) Project root (if config found in parents)
22
- // 2) Module root (if it has config - development mode)
23
- // 3) ~/.invoicer (global installation)
24
- const projectRoot = foundRoot ?? (hasModuleConfig ? moduleRoot : path.join(homedir(), ".invoicer"));
25
- // Ensure ~/.invoicer directory and data subdirectory exist when using home directory
26
- if (!foundRoot && !hasModuleConfig) {
22
+ // Get default app data directory (matching desktop app behavior)
23
+ const getDefaultDataDir = () => {
24
+ const osType = platform();
25
+ if (osType === "win32") {
26
+ // Windows: %APPDATA%\invoicer
27
+ const appdata = process.env.APPDATA;
28
+ if (appdata)
29
+ return path.join(appdata, "invoicer");
30
+ }
31
+ // macOS and Linux: ~/.local/share/invoicer (XDG Base Directory spec)
32
+ const xdgDataHome = process.env.XDG_DATA_HOME;
33
+ if (xdgDataHome)
34
+ return path.join(xdgDataHome, "invoicer");
35
+ return path.join(homedir(), ".local", "share", "invoicer");
36
+ };
37
+ // Priority: 1) Custom data path (if user set via `invoicer workspace --set`)
38
+ // 2) Project root (if config found in parents)
39
+ // 3) Module root (if it has config - development mode)
40
+ // 4) System app data directory (matches desktop app)
41
+ const customPath = getCustomDataPath();
42
+ const projectRoot = customPath ?? foundRoot ?? (hasModuleConfig ? moduleRoot : getDefaultDataDir());
43
+ // Ensure data subdirectory exists when using app data directory
44
+ if (!customPath && !foundRoot && !hasModuleConfig) {
27
45
  const dataDir = path.join(projectRoot, "data");
28
46
  if (!fs.existsSync(dataDir)) {
29
47
  fs.mkdirSync(dataDir, { recursive: true });
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/core/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAalC,MAAM,UAAU,eAAe,CAAC,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE;IACtD,IAAI,UAAU,GAAG,QAAQ,CAAC;IAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC;IAEzC,OAAO,UAAU,KAAK,IAAI,EAAE,CAAC;QAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;QACxD,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9B,OAAO,UAAU,CAAC;QACpB,CAAC;QACD,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE;IACzD,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC1F,MAAM,SAAS,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,eAAe,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC;IAE5E,yDAAyD;IACzD,iEAAiE;IACjE,iDAAiD;IACjD,MAAM,WAAW,GAAG,SAAS,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC;IAEpG,qFAAqF;IACrF,IAAI,CAAC,SAAS,IAAI,CAAC,eAAe,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAC/C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,OAAO;QACL,WAAW;QACX,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC;QACjD,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,CAAC;QACrD,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,gBAAgB,CAAC;QAC/D,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,cAAc,CAAC;QAC3D,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,aAAa,CAAC;QACzD,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC;QACrC,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC;KACnD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/core/paths.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,99 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { homedir } from "node:os";
4
+ function getSettingsDir() {
5
+ // Use same config location as desktop app for consistency
6
+ const osType = process.platform;
7
+ if (osType === "win32") {
8
+ const appdata = process.env.APPDATA;
9
+ if (appdata)
10
+ return path.join(appdata, "invoicer");
11
+ }
12
+ const xdgConfigHome = process.env.XDG_CONFIG_HOME;
13
+ if (xdgConfigHome)
14
+ return path.join(xdgConfigHome, "invoicer");
15
+ return path.join(homedir(), ".config", "invoicer");
16
+ }
17
+ function getSettingsPath() {
18
+ const settingsDir = getSettingsDir();
19
+ return path.join(settingsDir, "cli-settings.json");
20
+ }
21
+ export function loadCliSettings() {
22
+ const settingsPath = getSettingsPath();
23
+ if (!fs.existsSync(settingsPath)) {
24
+ return { version: 1 };
25
+ }
26
+ try {
27
+ const data = fs.readFileSync(settingsPath, "utf-8");
28
+ const parsed = JSON.parse(data);
29
+ // Validate required fields
30
+ if (typeof parsed.version !== "number") {
31
+ throw new Error("Invalid settings: missing or invalid version field");
32
+ }
33
+ return parsed;
34
+ }
35
+ catch (error) {
36
+ const message = error instanceof Error ? error.message : String(error);
37
+ console.error(`āš ļø Could not read CLI settings (${message}), using defaults`);
38
+ return { version: 1 };
39
+ }
40
+ }
41
+ export function saveCliSettings(settings) {
42
+ const settingsPath = getSettingsPath();
43
+ const settingsDir = path.dirname(settingsPath);
44
+ // Ensure directory exists
45
+ if (!fs.existsSync(settingsDir)) {
46
+ fs.mkdirSync(settingsDir, { recursive: true });
47
+ }
48
+ const json = JSON.stringify(settings, null, 2);
49
+ fs.writeFileSync(settingsPath, json, "utf-8");
50
+ }
51
+ export function getCustomDataPath() {
52
+ const settings = loadCliSettings();
53
+ if (!settings.customDataPath)
54
+ return null;
55
+ // Validate path still exists
56
+ if (fs.existsSync(settings.customDataPath)) {
57
+ return settings.customDataPath;
58
+ }
59
+ // Path no longer exists, clear it
60
+ settings.customDataPath = undefined;
61
+ saveCliSettings(settings);
62
+ return null;
63
+ }
64
+ export function setCustomDataPath(customPath) {
65
+ const resolvedPath = path.resolve(customPath);
66
+ // Ensure path exists and is a directory
67
+ if (!fs.existsSync(resolvedPath)) {
68
+ throw new Error(`Path does not exist: ${customPath}`);
69
+ }
70
+ const stat = fs.statSync(resolvedPath);
71
+ if (!stat.isDirectory()) {
72
+ throw new Error(`Path is not a directory: ${customPath}`);
73
+ }
74
+ // Check write permissions
75
+ try {
76
+ fs.accessSync(resolvedPath, fs.constants.W_OK);
77
+ }
78
+ catch {
79
+ throw new Error(`Path is not writable: ${customPath}`);
80
+ }
81
+ // Resolve symlinks to get canonical path
82
+ let canonicalPath = resolvedPath;
83
+ try {
84
+ canonicalPath = fs.realpathSync(resolvedPath);
85
+ }
86
+ catch {
87
+ // If canonicalization fails, use the resolved path anyway
88
+ console.warn(`āš ļø Could not resolve symlinks for ${resolvedPath}, using as-is`);
89
+ }
90
+ const settings = loadCliSettings();
91
+ settings.customDataPath = canonicalPath;
92
+ saveCliSettings(settings);
93
+ }
94
+ export function clearCustomDataPath() {
95
+ const settings = loadCliSettings();
96
+ settings.customDataPath = undefined;
97
+ saveCliSettings(settings);
98
+ }
99
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/core/settings.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@invoicer/cli",
3
- "version": "1.2.5",
3
+ "version": "1.3.0",
4
4
  "description": "Professional invoice generator with timesheet integration and CLI support",
5
5
  "homepage": "https://invoicer.inbrief.sh/",
6
6
  "repository": {