@indigoai-us/hq-cli 5.1.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 (102) hide show
  1. package/dist/__tests__/credentials.test.d.ts +5 -0
  2. package/dist/__tests__/credentials.test.d.ts.map +1 -0
  3. package/dist/__tests__/credentials.test.js +169 -0
  4. package/dist/__tests__/credentials.test.js.map +1 -0
  5. package/dist/commands/add.d.ts +6 -0
  6. package/dist/commands/add.d.ts.map +1 -0
  7. package/dist/commands/add.js +60 -0
  8. package/dist/commands/add.js.map +1 -0
  9. package/dist/commands/auth.d.ts +17 -0
  10. package/dist/commands/auth.d.ts.map +1 -0
  11. package/dist/commands/auth.js +269 -0
  12. package/dist/commands/auth.js.map +1 -0
  13. package/dist/commands/cloud-setup.d.ts +19 -0
  14. package/dist/commands/cloud-setup.d.ts.map +1 -0
  15. package/dist/commands/cloud-setup.js +206 -0
  16. package/dist/commands/cloud-setup.js.map +1 -0
  17. package/dist/commands/cloud.d.ts +16 -0
  18. package/dist/commands/cloud.d.ts.map +1 -0
  19. package/dist/commands/cloud.js +263 -0
  20. package/dist/commands/cloud.js.map +1 -0
  21. package/dist/commands/initial-upload.d.ts +67 -0
  22. package/dist/commands/initial-upload.d.ts.map +1 -0
  23. package/dist/commands/initial-upload.js +205 -0
  24. package/dist/commands/initial-upload.js.map +1 -0
  25. package/dist/commands/list.d.ts +6 -0
  26. package/dist/commands/list.d.ts.map +1 -0
  27. package/dist/commands/list.js +55 -0
  28. package/dist/commands/list.js.map +1 -0
  29. package/dist/commands/sync.d.ts +6 -0
  30. package/dist/commands/sync.d.ts.map +1 -0
  31. package/dist/commands/sync.js +104 -0
  32. package/dist/commands/sync.js.map +1 -0
  33. package/dist/commands/update.d.ts +7 -0
  34. package/dist/commands/update.d.ts.map +1 -0
  35. package/dist/commands/update.js +60 -0
  36. package/dist/commands/update.js.map +1 -0
  37. package/dist/index.d.ts +6 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +36 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/strategies/link.d.ts +7 -0
  42. package/dist/strategies/link.d.ts.map +1 -0
  43. package/dist/strategies/link.js +51 -0
  44. package/dist/strategies/link.js.map +1 -0
  45. package/dist/strategies/merge.d.ts +7 -0
  46. package/dist/strategies/merge.d.ts.map +1 -0
  47. package/dist/strategies/merge.js +110 -0
  48. package/dist/strategies/merge.js.map +1 -0
  49. package/dist/sync-worker.d.ts +11 -0
  50. package/dist/sync-worker.d.ts.map +1 -0
  51. package/dist/sync-worker.js +77 -0
  52. package/dist/sync-worker.js.map +1 -0
  53. package/dist/types.d.ts +41 -0
  54. package/dist/types.d.ts.map +1 -0
  55. package/dist/types.js +5 -0
  56. package/dist/types.js.map +1 -0
  57. package/dist/utils/api-client.d.ts +26 -0
  58. package/dist/utils/api-client.d.ts.map +1 -0
  59. package/dist/utils/api-client.js +87 -0
  60. package/dist/utils/api-client.js.map +1 -0
  61. package/dist/utils/credentials.d.ts +44 -0
  62. package/dist/utils/credentials.d.ts.map +1 -0
  63. package/dist/utils/credentials.js +101 -0
  64. package/dist/utils/credentials.js.map +1 -0
  65. package/dist/utils/git.d.ts +13 -0
  66. package/dist/utils/git.d.ts.map +1 -0
  67. package/dist/utils/git.js +70 -0
  68. package/dist/utils/git.js.map +1 -0
  69. package/dist/utils/manifest.d.ts +16 -0
  70. package/dist/utils/manifest.d.ts.map +1 -0
  71. package/dist/utils/manifest.js +95 -0
  72. package/dist/utils/manifest.js.map +1 -0
  73. package/dist/utils/sync.d.ts +125 -0
  74. package/dist/utils/sync.d.ts.map +1 -0
  75. package/dist/utils/sync.js +291 -0
  76. package/dist/utils/sync.js.map +1 -0
  77. package/package.json +36 -0
  78. package/src/__tests__/cloud-setup.test.ts +117 -0
  79. package/src/__tests__/credentials.test.ts +203 -0
  80. package/src/__tests__/initial-upload.test.ts +414 -0
  81. package/src/__tests__/sync.test.ts +627 -0
  82. package/src/commands/add.ts +74 -0
  83. package/src/commands/auth.ts +303 -0
  84. package/src/commands/cloud-setup.ts +251 -0
  85. package/src/commands/cloud.ts +300 -0
  86. package/src/commands/initial-upload.ts +263 -0
  87. package/src/commands/list.ts +66 -0
  88. package/src/commands/sync.ts +149 -0
  89. package/src/commands/update.ts +71 -0
  90. package/src/hq-cloud.d.ts +19 -0
  91. package/src/index.ts +46 -0
  92. package/src/strategies/link.ts +62 -0
  93. package/src/strategies/merge.ts +142 -0
  94. package/src/sync-worker.ts +82 -0
  95. package/src/types.ts +47 -0
  96. package/src/utils/api-client.ts +111 -0
  97. package/src/utils/credentials.ts +124 -0
  98. package/src/utils/git.ts +74 -0
  99. package/src/utils/manifest.ts +111 -0
  100. package/src/utils/sync.ts +381 -0
  101. package/tsconfig.json +9 -0
  102. package/vitest.config.ts +8 -0
@@ -0,0 +1,16 @@
1
+ import type { ModulesManifest, ModuleDefinition, ModuleLock, SyncState } from '../types.js';
2
+ export declare function findHqRoot(): string;
3
+ export declare function getManifestPath(hqRoot: string): string;
4
+ export declare function getLockPath(hqRoot: string): string;
5
+ export declare function getStatePath(hqRoot: string): string;
6
+ export declare function getModulesDir(hqRoot: string): string;
7
+ export declare function readManifest(hqRoot: string): ModulesManifest | null;
8
+ export declare function writeManifest(hqRoot: string, manifest: ModulesManifest): void;
9
+ export declare function readLock(hqRoot: string): ModuleLock | null;
10
+ export declare function writeLock(hqRoot: string, lock: ModuleLock): void;
11
+ export declare function readState(hqRoot: string): SyncState | null;
12
+ export declare function writeState(hqRoot: string, state: SyncState): void;
13
+ export declare function addModule(hqRoot: string, module: ModuleDefinition): void;
14
+ export declare function parseRepoName(repoUrl: string): string;
15
+ export declare function isValidRepoUrl(url: string): boolean;
16
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/utils/manifest.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAM5F,wBAAgB,UAAU,IAAI,MAAM,CAWnC;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAOnE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,IAAI,CAI7E;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAO1D;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAIhE;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAO1D;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI,CAGjE;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAaxE;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CASrD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEnD"}
@@ -0,0 +1,95 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import * as yaml from 'js-yaml';
4
+ const MANIFEST_FILE = 'modules.yaml';
5
+ const LOCK_FILE = 'modules.lock';
6
+ const STATE_FILE = '.hq-sync-state.json';
7
+ export function findHqRoot() {
8
+ let dir = process.cwd();
9
+ while (true) {
10
+ if (fs.existsSync(path.join(dir, '.claude')) || fs.existsSync(path.join(dir, 'workers'))) {
11
+ return dir;
12
+ }
13
+ const parent = path.dirname(dir);
14
+ if (parent === dir)
15
+ break; // Reached filesystem root (works on Windows and Unix)
16
+ dir = parent;
17
+ }
18
+ return process.cwd();
19
+ }
20
+ export function getManifestPath(hqRoot) {
21
+ return path.join(hqRoot, MANIFEST_FILE);
22
+ }
23
+ export function getLockPath(hqRoot) {
24
+ return path.join(hqRoot, LOCK_FILE);
25
+ }
26
+ export function getStatePath(hqRoot) {
27
+ return path.join(hqRoot, STATE_FILE);
28
+ }
29
+ export function getModulesDir(hqRoot) {
30
+ return path.join(hqRoot, 'modules');
31
+ }
32
+ export function readManifest(hqRoot) {
33
+ const manifestPath = getManifestPath(hqRoot);
34
+ if (!fs.existsSync(manifestPath)) {
35
+ return null;
36
+ }
37
+ const content = fs.readFileSync(manifestPath, 'utf-8');
38
+ return yaml.load(content);
39
+ }
40
+ export function writeManifest(hqRoot, manifest) {
41
+ const manifestPath = getManifestPath(hqRoot);
42
+ const content = yaml.dump(manifest, { lineWidth: -1 });
43
+ fs.writeFileSync(manifestPath, content);
44
+ }
45
+ export function readLock(hqRoot) {
46
+ const lockPath = getLockPath(hqRoot);
47
+ if (!fs.existsSync(lockPath)) {
48
+ return null;
49
+ }
50
+ const content = fs.readFileSync(lockPath, 'utf-8');
51
+ return yaml.load(content);
52
+ }
53
+ export function writeLock(hqRoot, lock) {
54
+ const lockPath = getLockPath(hqRoot);
55
+ const content = yaml.dump(lock, { lineWidth: -1 });
56
+ fs.writeFileSync(lockPath, content);
57
+ }
58
+ export function readState(hqRoot) {
59
+ const statePath = getStatePath(hqRoot);
60
+ if (!fs.existsSync(statePath)) {
61
+ return null;
62
+ }
63
+ const content = fs.readFileSync(statePath, 'utf-8');
64
+ return JSON.parse(content);
65
+ }
66
+ export function writeState(hqRoot, state) {
67
+ const statePath = getStatePath(hqRoot);
68
+ fs.writeFileSync(statePath, JSON.stringify(state, null, 2));
69
+ }
70
+ export function addModule(hqRoot, module) {
71
+ let manifest = readManifest(hqRoot);
72
+ if (!manifest) {
73
+ manifest = { version: '1', modules: [] };
74
+ }
75
+ // Check for duplicates
76
+ if (manifest.modules.some(m => m.name === module.name)) {
77
+ throw new Error(`Module "${module.name}" already exists`);
78
+ }
79
+ manifest.modules.push(module);
80
+ writeManifest(hqRoot, manifest);
81
+ }
82
+ export function parseRepoName(repoUrl) {
83
+ // Extract repo name from URL
84
+ // https://github.com/user/repo.git -> repo
85
+ // git@github.com:user/repo.git -> repo
86
+ const match = repoUrl.match(/[\/:]([^\/]+?)(\.git)?$/);
87
+ if (!match) {
88
+ throw new Error(`Cannot parse repo name from: ${repoUrl}`);
89
+ }
90
+ return match[1];
91
+ }
92
+ export function isValidRepoUrl(url) {
93
+ return url.startsWith('https://') || url.startsWith('git@');
94
+ }
95
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/utils/manifest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Sync utilities for hq-cloud file synchronization.
3
+ *
4
+ * Provides local manifest computation, file hashing, upload/download helpers,
5
+ * and diff computation via the API proxy. No AWS credentials needed — all
6
+ * operations go through the authenticated hq-cloud API.
7
+ */
8
+ /**
9
+ * Check whether a relative path should be ignored during sync.
10
+ */
11
+ export declare function shouldIgnore(relativePath: string): boolean;
12
+ /**
13
+ * Compute the SHA-256 hash of a file's contents.
14
+ */
15
+ export declare function hashFile(filePath: string): string;
16
+ /**
17
+ * Compute the SHA-256 hash of a buffer.
18
+ */
19
+ export declare function hashBuffer(content: Buffer): string;
20
+ /** A single entry in the local file manifest. */
21
+ export interface ManifestEntry {
22
+ /** Relative path from HQ root (forward slashes) */
23
+ path: string;
24
+ /** SHA-256 hash of file content */
25
+ hash: string;
26
+ /** File size in bytes */
27
+ size: number;
28
+ /** Last modified time (ISO string) */
29
+ lastModified: string;
30
+ }
31
+ /** Response from POST /api/files/sync */
32
+ export interface SyncDiffResult {
33
+ /** Relative paths that the client should upload (local is newer) */
34
+ toUpload: string[];
35
+ /** Relative paths that the client should download (remote is newer) */
36
+ toDownload: string[];
37
+ }
38
+ /** Response from GET /api/files/quota */
39
+ export interface QuotaInfo {
40
+ used: number;
41
+ limit: number;
42
+ percentage: number;
43
+ }
44
+ /** Sync state persisted to .hq-cloud-sync.json */
45
+ export interface CloudSyncState {
46
+ /** Whether a background sync watcher is running */
47
+ running: boolean;
48
+ /** PID of the background watcher process (if running) */
49
+ pid?: number;
50
+ /** ISO timestamp of last successful sync */
51
+ lastSync?: string;
52
+ /** Number of files tracked at last sync */
53
+ fileCount?: number;
54
+ /** Errors from last sync attempt */
55
+ errors: string[];
56
+ }
57
+ /**
58
+ * Recursively walk a directory and collect all files, respecting ignore rules.
59
+ * Returns paths relative to rootDir, using forward slashes.
60
+ */
61
+ export declare function walkDir(rootDir: string, subDir?: string): string[];
62
+ /**
63
+ * Compute the local file manifest for an HQ root directory.
64
+ * Walks all non-ignored files, computes hashes, and returns manifest entries.
65
+ */
66
+ export declare function computeLocalManifest(hqRoot: string): ManifestEntry[];
67
+ /**
68
+ * Compute the diff between local and remote state via the API.
69
+ * Sends the local manifest to POST /api/files/sync and receives
70
+ * lists of files to upload and download.
71
+ */
72
+ export declare function syncDiff(hqRoot: string): Promise<SyncDiffResult>;
73
+ /**
74
+ * Upload a single file to the cloud via POST /api/files/upload.
75
+ * File content is base64-encoded in the request body.
76
+ */
77
+ export declare function uploadFile(filePath: string, hqRoot: string): Promise<void>;
78
+ /**
79
+ * Download a single file from the cloud via GET /api/files/download.
80
+ * Writes the file to the local HQ root, creating directories as needed.
81
+ */
82
+ export declare function downloadFile(remotePath: string, hqRoot: string): Promise<void>;
83
+ /**
84
+ * Get storage quota information from the API.
85
+ */
86
+ export declare function getQuota(): Promise<QuotaInfo>;
87
+ /**
88
+ * Get the path to the sync state file.
89
+ */
90
+ export declare function getSyncStatePath(hqRoot: string): string;
91
+ /**
92
+ * Read the persisted sync state. Returns a default state if no file exists.
93
+ */
94
+ export declare function readSyncState(hqRoot: string): CloudSyncState;
95
+ /**
96
+ * Write the sync state to disk.
97
+ */
98
+ export declare function writeSyncState(hqRoot: string, state: CloudSyncState): void;
99
+ /**
100
+ * Push all changed local files to the cloud.
101
+ * Uses the sync diff endpoint to determine what needs uploading, then uploads each file.
102
+ * Returns the number of files uploaded.
103
+ */
104
+ export declare function pushChanges(hqRoot: string): Promise<{
105
+ uploaded: number;
106
+ errors: string[];
107
+ }>;
108
+ /**
109
+ * Pull all changed remote files to local.
110
+ * Uses the sync diff endpoint to determine what needs downloading, then downloads each file.
111
+ * Returns the number of files downloaded.
112
+ */
113
+ export declare function pullChanges(hqRoot: string): Promise<{
114
+ downloaded: number;
115
+ errors: string[];
116
+ }>;
117
+ /**
118
+ * Run a full bidirectional sync: upload local changes, then download remote changes.
119
+ */
120
+ export declare function fullSync(hqRoot: string): Promise<{
121
+ uploaded: number;
122
+ downloaded: number;
123
+ errors: string[];
124
+ }>;
125
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/utils/sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,291 @@
1
+ /**
2
+ * Sync utilities for hq-cloud file synchronization.
3
+ *
4
+ * Provides local manifest computation, file hashing, upload/download helpers,
5
+ * and diff computation via the API proxy. No AWS credentials needed — all
6
+ * operations go through the authenticated hq-cloud API.
7
+ */
8
+ import * as fs from 'fs';
9
+ import * as path from 'path';
10
+ import * as crypto from 'crypto';
11
+ import { apiRequest } from './api-client.js';
12
+ // ── Ignore patterns ──────────────────────────────────────────────────────────
13
+ /** Directories and patterns to skip during local file scanning. */
14
+ const IGNORE_DIRS = new Set([
15
+ '.git',
16
+ 'node_modules',
17
+ '.claude',
18
+ 'dist',
19
+ 'cdk.out',
20
+ '.next',
21
+ '__pycache__',
22
+ '.turbo',
23
+ ]);
24
+ /** File extensions to skip. */
25
+ const IGNORE_EXTENSIONS = new Set([
26
+ '.log',
27
+ ]);
28
+ /** Top-level files to skip. */
29
+ const IGNORE_FILES = new Set([
30
+ '.DS_Store',
31
+ 'Thumbs.db',
32
+ '.env',
33
+ '.env.local',
34
+ ]);
35
+ /**
36
+ * Check whether a relative path should be ignored during sync.
37
+ */
38
+ export function shouldIgnore(relativePath) {
39
+ const parts = relativePath.split(/[/\\]/);
40
+ // Skip if any path segment matches an ignored directory
41
+ for (const part of parts) {
42
+ if (IGNORE_DIRS.has(part)) {
43
+ return true;
44
+ }
45
+ }
46
+ // Skip ignored file names
47
+ const fileName = parts[parts.length - 1];
48
+ if (IGNORE_FILES.has(fileName)) {
49
+ return true;
50
+ }
51
+ // Skip ignored extensions
52
+ const ext = path.extname(fileName).toLowerCase();
53
+ if (IGNORE_EXTENSIONS.has(ext)) {
54
+ return true;
55
+ }
56
+ return false;
57
+ }
58
+ // ── File hashing ─────────────────────────────────────────────────────────────
59
+ /**
60
+ * Compute the SHA-256 hash of a file's contents.
61
+ */
62
+ export function hashFile(filePath) {
63
+ const content = fs.readFileSync(filePath);
64
+ return crypto.createHash('sha256').update(content).digest('hex');
65
+ }
66
+ /**
67
+ * Compute the SHA-256 hash of a buffer.
68
+ */
69
+ export function hashBuffer(content) {
70
+ return crypto.createHash('sha256').update(content).digest('hex');
71
+ }
72
+ // ── Local manifest computation ───────────────────────────────────────────────
73
+ /**
74
+ * Recursively walk a directory and collect all files, respecting ignore rules.
75
+ * Returns paths relative to rootDir, using forward slashes.
76
+ */
77
+ export function walkDir(rootDir, subDir = '') {
78
+ const results = [];
79
+ const absDir = subDir ? path.join(rootDir, subDir) : rootDir;
80
+ let entries;
81
+ try {
82
+ entries = fs.readdirSync(absDir, { withFileTypes: true });
83
+ }
84
+ catch {
85
+ return results;
86
+ }
87
+ for (const entry of entries) {
88
+ const relativePath = subDir
89
+ ? `${subDir}/${entry.name}`
90
+ : entry.name;
91
+ if (entry.isDirectory()) {
92
+ if (!IGNORE_DIRS.has(entry.name)) {
93
+ results.push(...walkDir(rootDir, relativePath));
94
+ }
95
+ }
96
+ else if (entry.isFile()) {
97
+ if (!shouldIgnore(relativePath)) {
98
+ results.push(relativePath);
99
+ }
100
+ }
101
+ // Skip symlinks, sockets, etc.
102
+ }
103
+ return results;
104
+ }
105
+ /**
106
+ * Compute the local file manifest for an HQ root directory.
107
+ * Walks all non-ignored files, computes hashes, and returns manifest entries.
108
+ */
109
+ export function computeLocalManifest(hqRoot) {
110
+ const files = walkDir(hqRoot);
111
+ const manifest = [];
112
+ for (const relativePath of files) {
113
+ const absPath = path.join(hqRoot, relativePath);
114
+ try {
115
+ const stat = fs.statSync(absPath);
116
+ const hash = hashFile(absPath);
117
+ manifest.push({
118
+ path: relativePath,
119
+ hash,
120
+ size: stat.size,
121
+ lastModified: stat.mtime.toISOString(),
122
+ });
123
+ }
124
+ catch {
125
+ // File may have been deleted between walk and stat — skip
126
+ }
127
+ }
128
+ return manifest;
129
+ }
130
+ // ── API operations ───────────────────────────────────────────────────────────
131
+ /**
132
+ * Compute the diff between local and remote state via the API.
133
+ * Sends the local manifest to POST /api/files/sync and receives
134
+ * lists of files to upload and download.
135
+ */
136
+ export async function syncDiff(hqRoot) {
137
+ const manifest = computeLocalManifest(hqRoot);
138
+ const resp = await apiRequest('POST', '/api/files/sync', { manifest });
139
+ if (!resp.ok || !resp.data) {
140
+ throw new Error(`Sync diff failed: ${resp.error ?? `HTTP ${resp.status}`}`);
141
+ }
142
+ return resp.data;
143
+ }
144
+ /**
145
+ * Upload a single file to the cloud via POST /api/files/upload.
146
+ * File content is base64-encoded in the request body.
147
+ */
148
+ export async function uploadFile(filePath, hqRoot) {
149
+ const absPath = path.join(hqRoot, filePath);
150
+ const content = fs.readFileSync(absPath);
151
+ const stat = fs.statSync(absPath);
152
+ const resp = await apiRequest('POST', '/api/files/upload', {
153
+ path: filePath,
154
+ content: content.toString('base64'),
155
+ size: stat.size,
156
+ });
157
+ if (!resp.ok) {
158
+ throw new Error(`Upload failed for ${filePath}: ${resp.error ?? `HTTP ${resp.status}`}`);
159
+ }
160
+ }
161
+ /**
162
+ * Download a single file from the cloud via GET /api/files/download.
163
+ * Writes the file to the local HQ root, creating directories as needed.
164
+ */
165
+ export async function downloadFile(remotePath, hqRoot) {
166
+ const encodedPath = encodeURIComponent(remotePath);
167
+ const resp = await apiRequest('GET', `/api/files/download?path=${encodedPath}`);
168
+ if (!resp.ok || !resp.data) {
169
+ throw new Error(`Download failed for ${remotePath}: ${resp.error ?? `HTTP ${resp.status}`}`);
170
+ }
171
+ const absPath = path.join(hqRoot, remotePath);
172
+ const dir = path.dirname(absPath);
173
+ if (!fs.existsSync(dir)) {
174
+ fs.mkdirSync(dir, { recursive: true });
175
+ }
176
+ const buffer = Buffer.from(resp.data.content, 'base64');
177
+ fs.writeFileSync(absPath, buffer);
178
+ }
179
+ /**
180
+ * Get storage quota information from the API.
181
+ */
182
+ export async function getQuota() {
183
+ const resp = await apiRequest('GET', '/api/files/quota');
184
+ if (!resp.ok || !resp.data) {
185
+ throw new Error(`Quota check failed: ${resp.error ?? `HTTP ${resp.status}`}`);
186
+ }
187
+ return resp.data;
188
+ }
189
+ // ── Sync state management ────────────────────────────────────────────────────
190
+ const SYNC_STATE_FILE = '.hq-cloud-sync.json';
191
+ /**
192
+ * Get the path to the sync state file.
193
+ */
194
+ export function getSyncStatePath(hqRoot) {
195
+ return path.join(hqRoot, SYNC_STATE_FILE);
196
+ }
197
+ /**
198
+ * Read the persisted sync state. Returns a default state if no file exists.
199
+ */
200
+ export function readSyncState(hqRoot) {
201
+ const statePath = getSyncStatePath(hqRoot);
202
+ try {
203
+ if (fs.existsSync(statePath)) {
204
+ const raw = fs.readFileSync(statePath, 'utf-8');
205
+ return JSON.parse(raw);
206
+ }
207
+ }
208
+ catch {
209
+ // Corrupted state file — return default
210
+ }
211
+ return { running: false, errors: [] };
212
+ }
213
+ /**
214
+ * Write the sync state to disk.
215
+ */
216
+ export function writeSyncState(hqRoot, state) {
217
+ const statePath = getSyncStatePath(hqRoot);
218
+ fs.writeFileSync(statePath, JSON.stringify(state, null, 2));
219
+ }
220
+ // ── Full push / pull operations ──────────────────────────────────────────────
221
+ /**
222
+ * Push all changed local files to the cloud.
223
+ * Uses the sync diff endpoint to determine what needs uploading, then uploads each file.
224
+ * Returns the number of files uploaded.
225
+ */
226
+ export async function pushChanges(hqRoot) {
227
+ const diff = await syncDiff(hqRoot);
228
+ const errors = [];
229
+ let uploaded = 0;
230
+ for (const filePath of diff.toUpload) {
231
+ try {
232
+ await uploadFile(filePath, hqRoot);
233
+ uploaded++;
234
+ }
235
+ catch (err) {
236
+ errors.push(err instanceof Error ? err.message : String(err));
237
+ }
238
+ }
239
+ return { uploaded, errors };
240
+ }
241
+ /**
242
+ * Pull all changed remote files to local.
243
+ * Uses the sync diff endpoint to determine what needs downloading, then downloads each file.
244
+ * Returns the number of files downloaded.
245
+ */
246
+ export async function pullChanges(hqRoot) {
247
+ const diff = await syncDiff(hqRoot);
248
+ const errors = [];
249
+ let downloaded = 0;
250
+ for (const filePath of diff.toDownload) {
251
+ try {
252
+ await downloadFile(filePath, hqRoot);
253
+ downloaded++;
254
+ }
255
+ catch (err) {
256
+ errors.push(err instanceof Error ? err.message : String(err));
257
+ }
258
+ }
259
+ return { downloaded, errors };
260
+ }
261
+ /**
262
+ * Run a full bidirectional sync: upload local changes, then download remote changes.
263
+ */
264
+ export async function fullSync(hqRoot) {
265
+ const diff = await syncDiff(hqRoot);
266
+ const errors = [];
267
+ let uploaded = 0;
268
+ let downloaded = 0;
269
+ // Upload first
270
+ for (const filePath of diff.toUpload) {
271
+ try {
272
+ await uploadFile(filePath, hqRoot);
273
+ uploaded++;
274
+ }
275
+ catch (err) {
276
+ errors.push(err instanceof Error ? err.message : String(err));
277
+ }
278
+ }
279
+ // Then download
280
+ for (const filePath of diff.toDownload) {
281
+ try {
282
+ await downloadFile(filePath, hqRoot);
283
+ downloaded++;
284
+ }
285
+ catch (err) {
286
+ errors.push(err instanceof Error ? err.message : String(err));
287
+ }
288
+ }
289
+ return { uploaded, downloaded, errors };
290
+ }
291
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/utils/sync.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,gFAAgF;AAEhF,mEAAmE;AACnE,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC;IAC1B,MAAM;IACN,cAAc;IACd,SAAS;IACT,MAAM;IACN,SAAS;IACT,OAAO;IACP,aAAa;IACb,QAAQ;CACT,CAAC,CAAC;AAEH,+BAA+B;AAC/B,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IAChC,MAAM;CACP,CAAC,CAAC;AAEH,+BAA+B;AAC/B,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC;IAC3B,WAAW;IACX,WAAW;IACX,MAAM;IACN,YAAY;CACb,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,YAAoB;IAC/C,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAE1C,wDAAwD;IACxD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,0BAA0B;IAC1B,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzC,IAAI,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,0BAA0B;IAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACjD,IAAI,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,gFAAgF;AAEhF;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,QAAgB;IACvC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC1C,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACnE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACnE,CAAC;AA6CD,gFAAgF;AAEhF;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,OAAe,EAAE,SAAiB,EAAE;IAC1D,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAE7D,IAAI,OAAoB,CAAC;IACzB,IAAI,CAAC;QACH,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,YAAY,GAAG,MAAM;YACzB,CAAC,CAAC,GAAG,MAAM,IAAI,KAAK,CAAC,IAAI,EAAE;YAC3B,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;QAEf,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjC,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC;YAClD,CAAC;QACH,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1B,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,CAAC;gBAChC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QACD,+BAA+B;IACjC,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAc;IACjD,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9B,MAAM,QAAQ,GAAoB,EAAE,CAAC;IAErC,KAAK,MAAM,YAAY,IAAI,KAAK,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QAChD,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAClC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;YAC/B,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,YAAY;gBAClB,IAAI;gBACJ,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;aACvC,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,0DAA0D;QAC5D,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,gFAAgF;AAEhF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAc;IAC3C,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,MAAM,UAAU,CAAiB,MAAM,EAAE,iBAAiB,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;IAEvF,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,CAAC,KAAK,IAAI,QAAQ,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,OAAO,IAAI,CAAC,IAAI,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,QAAgB,EAAE,MAAc;IAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAElC,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,mBAAmB,EAAE;QACzD,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACnC,IAAI,EAAE,IAAI,CAAC,IAAI;KAChB,CAAC,CAAC;IAEH,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,KAAK,IAAI,CAAC,KAAK,IAAI,QAAQ,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC3F,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,UAAkB,EAAE,MAAc;IACnE,MAAM,WAAW,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,MAAM,UAAU,CAC3B,KAAK,EACL,4BAA4B,WAAW,EAAE,CAC1C,CAAC;IAEF,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,uBAAuB,UAAU,KAAK,IAAI,CAAC,KAAK,IAAI,QAAQ,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC/F,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAElC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACxD,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,MAAM,IAAI,GAAG,MAAM,UAAU,CAAY,KAAK,EAAE,kBAAkB,CAAC,CAAC;IAEpE,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,CAAC,KAAK,IAAI,QAAQ,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAChF,CAAC;IAED,OAAO,IAAI,CAAC,IAAI,CAAC;AACnB,CAAC;AAED,gFAAgF;AAEhF,MAAM,eAAe,GAAG,qBAAqB,CAAC;AAE9C;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,MAAM,SAAS,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC3C,IAAI,CAAC;QACH,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAChD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmB,CAAC;QAC3C,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,wCAAwC;IAC1C,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AACxC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,KAAqB;IAClE,MAAM,SAAS,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC3C,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9D,CAAC;AAED,gFAAgF;AAEhF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAc;IAC9C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QACrC,IAAI,CAAC;YACH,MAAM,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACnC,QAAQ,EAAE,CAAC;QACb,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAC9B,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAc;IAC9C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACvC,IAAI,CAAC;YACH,MAAM,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACrC,UAAU,EAAE,CAAC;QACf,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAc;IAC3C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,eAAe;IACf,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QACrC,IAAI,CAAC;YACH,MAAM,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACnC,QAAQ,EAAE,CAAC;QACb,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAED,gBAAgB;IAChB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACvC,IAAI,CAAC;YACH,MAAM,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACrC,UAAU,EAAE,CAAC;QACf,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;AAC1C,CAAC"}
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@indigoai-us/hq-cli",
3
+ "version": "5.1.0",
4
+ "description": "HQ management CLI — modules and cloud sync",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "hq": "dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "typecheck": "tsc --noEmit",
12
+ "clean": "rm -rf dist",
13
+ "test": "vitest run",
14
+ "test:watch": "vitest"
15
+ },
16
+ "dependencies": {
17
+ "chalk": "^5.3.0",
18
+ "commander": "^12.1.0",
19
+ "js-yaml": "^4.1.0",
20
+ "simple-git": "^3.27.0"
21
+ },
22
+ "devDependencies": {
23
+ "@types/js-yaml": "^4.0.9",
24
+ "@types/node": "^22.0.0",
25
+ "typescript": "^5.7.0",
26
+ "vitest": "^1.2.2"
27
+ },
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/indigoai-us/hq.git",
31
+ "directory": "packages/hq-cli"
32
+ },
33
+ "keywords": ["hq", "ai", "modules", "sync", "cloud"],
34
+ "license": "MIT",
35
+ "type": "module"
36
+ }