@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.
- package/dist/__tests__/credentials.test.d.ts +5 -0
- package/dist/__tests__/credentials.test.d.ts.map +1 -0
- package/dist/__tests__/credentials.test.js +169 -0
- package/dist/__tests__/credentials.test.js.map +1 -0
- package/dist/commands/add.d.ts +6 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +60 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/auth.d.ts +17 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +269 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/cloud-setup.d.ts +19 -0
- package/dist/commands/cloud-setup.d.ts.map +1 -0
- package/dist/commands/cloud-setup.js +206 -0
- package/dist/commands/cloud-setup.js.map +1 -0
- package/dist/commands/cloud.d.ts +16 -0
- package/dist/commands/cloud.d.ts.map +1 -0
- package/dist/commands/cloud.js +263 -0
- package/dist/commands/cloud.js.map +1 -0
- package/dist/commands/initial-upload.d.ts +67 -0
- package/dist/commands/initial-upload.d.ts.map +1 -0
- package/dist/commands/initial-upload.js +205 -0
- package/dist/commands/initial-upload.js.map +1 -0
- package/dist/commands/list.d.ts +6 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +55 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/sync.d.ts +6 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +104 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/update.d.ts +7 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +60 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/strategies/link.d.ts +7 -0
- package/dist/strategies/link.d.ts.map +1 -0
- package/dist/strategies/link.js +51 -0
- package/dist/strategies/link.js.map +1 -0
- package/dist/strategies/merge.d.ts +7 -0
- package/dist/strategies/merge.d.ts.map +1 -0
- package/dist/strategies/merge.js +110 -0
- package/dist/strategies/merge.js.map +1 -0
- package/dist/sync-worker.d.ts +11 -0
- package/dist/sync-worker.d.ts.map +1 -0
- package/dist/sync-worker.js +77 -0
- package/dist/sync-worker.js.map +1 -0
- package/dist/types.d.ts +41 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/api-client.d.ts +26 -0
- package/dist/utils/api-client.d.ts.map +1 -0
- package/dist/utils/api-client.js +87 -0
- package/dist/utils/api-client.js.map +1 -0
- package/dist/utils/credentials.d.ts +44 -0
- package/dist/utils/credentials.d.ts.map +1 -0
- package/dist/utils/credentials.js +101 -0
- package/dist/utils/credentials.js.map +1 -0
- package/dist/utils/git.d.ts +13 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +70 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/manifest.d.ts +16 -0
- package/dist/utils/manifest.d.ts.map +1 -0
- package/dist/utils/manifest.js +95 -0
- package/dist/utils/manifest.js.map +1 -0
- package/dist/utils/sync.d.ts +125 -0
- package/dist/utils/sync.d.ts.map +1 -0
- package/dist/utils/sync.js +291 -0
- package/dist/utils/sync.js.map +1 -0
- package/package.json +36 -0
- package/src/__tests__/cloud-setup.test.ts +117 -0
- package/src/__tests__/credentials.test.ts +203 -0
- package/src/__tests__/initial-upload.test.ts +414 -0
- package/src/__tests__/sync.test.ts +627 -0
- package/src/commands/add.ts +74 -0
- package/src/commands/auth.ts +303 -0
- package/src/commands/cloud-setup.ts +251 -0
- package/src/commands/cloud.ts +300 -0
- package/src/commands/initial-upload.ts +263 -0
- package/src/commands/list.ts +66 -0
- package/src/commands/sync.ts +149 -0
- package/src/commands/update.ts +71 -0
- package/src/hq-cloud.d.ts +19 -0
- package/src/index.ts +46 -0
- package/src/strategies/link.ts +62 -0
- package/src/strategies/merge.ts +142 -0
- package/src/sync-worker.ts +82 -0
- package/src/types.ts +47 -0
- package/src/utils/api-client.ts +111 -0
- package/src/utils/credentials.ts +124 -0
- package/src/utils/git.ts +74 -0
- package/src/utils/manifest.ts +111 -0
- package/src/utils/sync.ts +381 -0
- package/tsconfig.json +9 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Initial HQ file upload for first-time cloud setup.
|
|
3
|
+
*
|
|
4
|
+
* After Clerk auth and Claude token setup, this command uploads the user's
|
|
5
|
+
* local HQ files to the cloud so the first session has access to the workspace.
|
|
6
|
+
*
|
|
7
|
+
* Respects the same ignore rules as sync (shouldIgnore from utils/sync.ts):
|
|
8
|
+
* - .git/, node_modules/, .claude/, dist/, cdk.out/, etc.
|
|
9
|
+
* - .log files, .env files, .DS_Store, Thumbs.db
|
|
10
|
+
*
|
|
11
|
+
* Exports `runInitialUpload` so it can be called programmatically from the
|
|
12
|
+
* create-hq installer (US-004) or other commands.
|
|
13
|
+
*/
|
|
14
|
+
import * as readline from 'readline';
|
|
15
|
+
import chalk from 'chalk';
|
|
16
|
+
import { apiRequest } from '../utils/api-client.js';
|
|
17
|
+
import { walkDir, uploadFile, computeLocalManifest, readSyncState, writeSyncState, } from '../utils/sync.js';
|
|
18
|
+
/**
|
|
19
|
+
* Prompt the user with a yes/no question on stdin.
|
|
20
|
+
* Returns true for 'y'/'yes', false for 'n'/'no'.
|
|
21
|
+
* Defaults to defaultAnswer if user just presses Enter.
|
|
22
|
+
*/
|
|
23
|
+
export function promptYesNo(question, defaultAnswer = true) {
|
|
24
|
+
const hint = defaultAnswer ? '[Y/n]' : '[y/N]';
|
|
25
|
+
const rl = readline.createInterface({
|
|
26
|
+
input: process.stdin,
|
|
27
|
+
output: process.stdout,
|
|
28
|
+
});
|
|
29
|
+
return new Promise((resolve) => {
|
|
30
|
+
rl.question(`${question} ${hint} `, (answer) => {
|
|
31
|
+
rl.close();
|
|
32
|
+
const trimmed = answer.trim().toLowerCase();
|
|
33
|
+
if (trimmed === '') {
|
|
34
|
+
resolve(defaultAnswer);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
resolve(trimmed === 'y' || trimmed === 'yes');
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Prompt the user to choose between merge and replace.
|
|
44
|
+
* Returns 'merge' or 'replace'.
|
|
45
|
+
*/
|
|
46
|
+
export function promptMergeOrReplace() {
|
|
47
|
+
const rl = readline.createInterface({
|
|
48
|
+
input: process.stdin,
|
|
49
|
+
output: process.stdout,
|
|
50
|
+
});
|
|
51
|
+
return new Promise((resolve) => {
|
|
52
|
+
rl.question('Choose [m]erge or [r]eplace: ', (answer) => {
|
|
53
|
+
rl.close();
|
|
54
|
+
const trimmed = answer.trim().toLowerCase();
|
|
55
|
+
if (trimmed === 'r' || trimmed === 'replace') {
|
|
56
|
+
resolve('replace');
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
resolve('merge');
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Delete all remote files (used when user chooses 'replace').
|
|
66
|
+
*/
|
|
67
|
+
async function deleteRemoteFiles() {
|
|
68
|
+
const resp = await apiRequest('DELETE', '/api/files/all');
|
|
69
|
+
if (!resp.ok) {
|
|
70
|
+
throw new Error(`Failed to clear remote files: ${resp.error ?? `HTTP ${resp.status}`}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Write a progress line that overwrites the previous line.
|
|
75
|
+
* Falls back to newline output if stdout is not a TTY (e.g., in tests or pipes).
|
|
76
|
+
*/
|
|
77
|
+
export function writeProgress(current, total) {
|
|
78
|
+
const pct = total > 0 ? Math.round((current / total) * 100) : 0;
|
|
79
|
+
const line = `Uploading: ${current}/${total} files (${pct}%)`;
|
|
80
|
+
if (process.stdout.isTTY) {
|
|
81
|
+
process.stdout.write(`\r${line}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Run the initial HQ file upload.
|
|
86
|
+
*
|
|
87
|
+
* This is the core function that:
|
|
88
|
+
* 1. Lists remote files via GET /api/files/list
|
|
89
|
+
* 2. If remote has files, asks user to merge or replace
|
|
90
|
+
* 3. Walks local files (respecting ignore rules)
|
|
91
|
+
* 4. Uploads all files with progress indicator
|
|
92
|
+
* 5. Updates sync state
|
|
93
|
+
*
|
|
94
|
+
* @param hqRoot - Absolute path to the HQ root directory
|
|
95
|
+
* @param options - Optional overrides (for testing / programmatic use)
|
|
96
|
+
* @returns Upload result with counts and any errors
|
|
97
|
+
*/
|
|
98
|
+
export async function runInitialUpload(hqRoot, options) {
|
|
99
|
+
const quiet = options?.quiet ?? false;
|
|
100
|
+
const log = (msg) => {
|
|
101
|
+
if (!quiet)
|
|
102
|
+
console.log(msg);
|
|
103
|
+
};
|
|
104
|
+
// 1. Check remote state
|
|
105
|
+
log(chalk.blue('Checking cloud storage...'));
|
|
106
|
+
let remoteFiles = [];
|
|
107
|
+
try {
|
|
108
|
+
const resp = await apiRequest('GET', '/api/files/list');
|
|
109
|
+
if (resp.ok && resp.data) {
|
|
110
|
+
remoteFiles = resp.data.files ?? [];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// If the endpoint doesn't exist yet or fails, treat as empty
|
|
115
|
+
}
|
|
116
|
+
// 2. Handle existing remote files
|
|
117
|
+
if (remoteFiles.length > 0) {
|
|
118
|
+
log('');
|
|
119
|
+
log(chalk.yellow(`Cloud storage already has ${remoteFiles.length} file${remoteFiles.length !== 1 ? 's' : ''}.`));
|
|
120
|
+
let action;
|
|
121
|
+
if (options?.onConflict) {
|
|
122
|
+
action = options.onConflict;
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
log(' merge — Upload local files, keeping existing remote files');
|
|
126
|
+
log(' replace — Delete all remote files first, then upload');
|
|
127
|
+
log('');
|
|
128
|
+
action = await promptMergeOrReplace();
|
|
129
|
+
}
|
|
130
|
+
if (action === 'skip') {
|
|
131
|
+
log(chalk.dim('Skipping upload.'));
|
|
132
|
+
return { totalFiles: 0, uploaded: 0, failed: 0, errors: [], skipped: true };
|
|
133
|
+
}
|
|
134
|
+
if (action === 'replace') {
|
|
135
|
+
log(chalk.dim('Clearing remote files...'));
|
|
136
|
+
await deleteRemoteFiles();
|
|
137
|
+
log(chalk.dim('Remote files cleared.'));
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
log(chalk.dim('Merging: existing remote files will be preserved.'));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// 3. Walk local files
|
|
144
|
+
log(chalk.blue('Scanning local HQ files...'));
|
|
145
|
+
const localFiles = walkDir(hqRoot);
|
|
146
|
+
if (localFiles.length === 0) {
|
|
147
|
+
log(chalk.yellow('No files found to upload.'));
|
|
148
|
+
return { totalFiles: 0, uploaded: 0, failed: 0, errors: [], skipped: false };
|
|
149
|
+
}
|
|
150
|
+
log(chalk.dim(` Found ${localFiles.length} file${localFiles.length !== 1 ? 's' : ''} to upload`));
|
|
151
|
+
log('');
|
|
152
|
+
// 4. Upload with progress
|
|
153
|
+
const errors = [];
|
|
154
|
+
let uploaded = 0;
|
|
155
|
+
for (let i = 0; i < localFiles.length; i++) {
|
|
156
|
+
const filePath = localFiles[i];
|
|
157
|
+
if (!quiet) {
|
|
158
|
+
writeProgress(i + 1, localFiles.length);
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
await uploadFile(filePath, hqRoot);
|
|
162
|
+
uploaded++;
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
errors.push(`${filePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// Clear the progress line
|
|
169
|
+
if (!quiet && process.stdout.isTTY) {
|
|
170
|
+
process.stdout.write('\r' + ' '.repeat(60) + '\r');
|
|
171
|
+
}
|
|
172
|
+
// 5. Report results
|
|
173
|
+
if (errors.length === 0) {
|
|
174
|
+
log(chalk.green(`Uploaded ${uploaded}/${localFiles.length} files successfully.`));
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
log(chalk.green(`Uploaded ${uploaded}/${localFiles.length} files.`));
|
|
178
|
+
log(chalk.yellow(` ${errors.length} error${errors.length !== 1 ? 's' : ''}:`));
|
|
179
|
+
for (const err of errors.slice(0, 5)) {
|
|
180
|
+
log(chalk.red(` - ${err}`));
|
|
181
|
+
}
|
|
182
|
+
if (errors.length > 5) {
|
|
183
|
+
log(chalk.dim(` ... and ${errors.length - 5} more`));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// 6. Update sync state
|
|
187
|
+
const manifest = computeLocalManifest(hqRoot);
|
|
188
|
+
const state = readSyncState(hqRoot);
|
|
189
|
+
state.lastSync = new Date().toISOString();
|
|
190
|
+
state.fileCount = manifest.length;
|
|
191
|
+
state.errors = errors;
|
|
192
|
+
writeSyncState(hqRoot, state);
|
|
193
|
+
if (errors.length === 0) {
|
|
194
|
+
log('');
|
|
195
|
+
log(chalk.green('Sync status: in sync'));
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
totalFiles: localFiles.length,
|
|
199
|
+
uploaded,
|
|
200
|
+
failed: errors.length,
|
|
201
|
+
errors,
|
|
202
|
+
skipped: false,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=initial-upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"initial-upload.js","sourceRoot":"","sources":["../../src/commands/initial-upload.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuD1D"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hq modules list command (US-005)
|
|
3
|
+
*/
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import { findHqRoot, readManifest, readLock, getModulesDir } from '../utils/manifest.js';
|
|
6
|
+
import { isRepo, getCurrentCommit, isBehindRemote } from '../utils/git.js';
|
|
7
|
+
export function registerListCommand(program) {
|
|
8
|
+
program
|
|
9
|
+
.command('list')
|
|
10
|
+
.alias('ls')
|
|
11
|
+
.description('List all modules and their status')
|
|
12
|
+
.action(async () => {
|
|
13
|
+
try {
|
|
14
|
+
const hqRoot = findHqRoot();
|
|
15
|
+
const manifest = readManifest(hqRoot);
|
|
16
|
+
if (!manifest || manifest.modules.length === 0) {
|
|
17
|
+
console.log('No modules in manifest. Use "hq modules add" to add modules.');
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const modulesDir = getModulesDir(hqRoot);
|
|
21
|
+
const lock = readLock(hqRoot);
|
|
22
|
+
console.log('Modules:\n');
|
|
23
|
+
for (const module of manifest.modules) {
|
|
24
|
+
const moduleDir = path.join(modulesDir, module.name);
|
|
25
|
+
const installed = await isRepo(moduleDir);
|
|
26
|
+
console.log(` ${module.name}`);
|
|
27
|
+
console.log(` Repo: ${module.repo}`);
|
|
28
|
+
console.log(` Branch: ${module.branch || 'main'}`);
|
|
29
|
+
console.log(` Strategy: ${module.strategy}`);
|
|
30
|
+
console.log(` Paths: ${module.paths.map(p => `${p.src} -> ${p.dest}`).join(', ')}`);
|
|
31
|
+
if (installed) {
|
|
32
|
+
const commit = await getCurrentCommit(moduleDir);
|
|
33
|
+
const shortCommit = commit.slice(0, 7);
|
|
34
|
+
const lockedCommit = lock?.locked[module.name];
|
|
35
|
+
const isLocked = lockedCommit === commit;
|
|
36
|
+
console.log(` Status: ✓ installed @ ${shortCommit}${isLocked ? ' (locked)' : ''}`);
|
|
37
|
+
// Check if behind upstream
|
|
38
|
+
const { behind, commits } = await isBehindRemote(moduleDir);
|
|
39
|
+
if (behind) {
|
|
40
|
+
console.log(` Updates: ${commits} commit(s) behind remote`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
console.log(` Status: ✗ not installed`);
|
|
45
|
+
}
|
|
46
|
+
console.log();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsEpC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAwE1D"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hq modules sync command (US-004)
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import { findHqRoot, readManifest, readLock, writeLock, getModulesDir, } from '../utils/manifest.js';
|
|
7
|
+
import { cloneRepo, fetchRepo, pullRepo, getCurrentCommit, checkoutCommit, isRepo, ensureGitignore, } from '../utils/git.js';
|
|
8
|
+
import { linkSync } from '../strategies/link.js';
|
|
9
|
+
import { mergeSync } from '../strategies/merge.js';
|
|
10
|
+
async function syncModule(module, moduleDir, hqRoot, locked, lockData) {
|
|
11
|
+
const repoExists = await isRepo(moduleDir);
|
|
12
|
+
// Clone or fetch
|
|
13
|
+
if (!repoExists) {
|
|
14
|
+
console.log(` Cloning ${module.name}...`);
|
|
15
|
+
await cloneRepo(module.repo, moduleDir, module.branch);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
console.log(` Fetching ${module.name}...`);
|
|
19
|
+
await fetchRepo(moduleDir);
|
|
20
|
+
// Checkout locked commit if --locked
|
|
21
|
+
if (locked && lockData?.locked[module.name]) {
|
|
22
|
+
await checkoutCommit(moduleDir, lockData.locked[module.name]);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
await pullRepo(moduleDir);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Apply sync strategy
|
|
29
|
+
console.log(` Syncing with strategy: ${module.strategy}`);
|
|
30
|
+
let result;
|
|
31
|
+
switch (module.strategy) {
|
|
32
|
+
case 'link':
|
|
33
|
+
result = await linkSync(module, moduleDir, hqRoot);
|
|
34
|
+
break;
|
|
35
|
+
case 'merge':
|
|
36
|
+
case 'copy':
|
|
37
|
+
result = await mergeSync(module, moduleDir, hqRoot);
|
|
38
|
+
break;
|
|
39
|
+
default:
|
|
40
|
+
result = {
|
|
41
|
+
module: module.name,
|
|
42
|
+
success: false,
|
|
43
|
+
action: 'skipped',
|
|
44
|
+
message: `Unknown strategy: ${module.strategy}`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
export function registerSyncCommand(program) {
|
|
50
|
+
program
|
|
51
|
+
.command('sync')
|
|
52
|
+
.description('Sync all modules from manifest')
|
|
53
|
+
.option('--locked', 'Use locked versions from modules.lock')
|
|
54
|
+
.action(async (options) => {
|
|
55
|
+
try {
|
|
56
|
+
const hqRoot = findHqRoot();
|
|
57
|
+
const manifest = readManifest(hqRoot);
|
|
58
|
+
if (!manifest || manifest.modules.length === 0) {
|
|
59
|
+
console.log('No modules in manifest. Use "hq modules add" to add modules.');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const modulesDir = getModulesDir(hqRoot);
|
|
63
|
+
if (!fs.existsSync(modulesDir)) {
|
|
64
|
+
fs.mkdirSync(modulesDir, { recursive: true });
|
|
65
|
+
}
|
|
66
|
+
// Ensure modules/ is gitignored
|
|
67
|
+
ensureGitignore(hqRoot, 'modules/');
|
|
68
|
+
const lockData = options.locked ? readLock(hqRoot) : null;
|
|
69
|
+
const results = [];
|
|
70
|
+
const newLock = { version: '1', locked: {} };
|
|
71
|
+
console.log(`Syncing ${manifest.modules.length} module(s)...\n`);
|
|
72
|
+
for (const module of manifest.modules) {
|
|
73
|
+
console.log(`[${module.name}]`);
|
|
74
|
+
const moduleDir = path.join(modulesDir, module.name);
|
|
75
|
+
const result = await syncModule(module, moduleDir, hqRoot, options.locked ?? false, lockData);
|
|
76
|
+
results.push(result);
|
|
77
|
+
// Record commit for lock file
|
|
78
|
+
if (result.success) {
|
|
79
|
+
const commit = await getCurrentCommit(moduleDir);
|
|
80
|
+
newLock.locked[module.name] = commit;
|
|
81
|
+
}
|
|
82
|
+
const status = result.success ? '✓' : '✗';
|
|
83
|
+
const msg = result.message || `${result.filesChanged ?? 0} files`;
|
|
84
|
+
console.log(` ${status} ${result.action}: ${msg}\n`);
|
|
85
|
+
}
|
|
86
|
+
// Write lock file (US-008)
|
|
87
|
+
if (!options.locked) {
|
|
88
|
+
writeLock(hqRoot, newLock);
|
|
89
|
+
}
|
|
90
|
+
// Summary
|
|
91
|
+
const success = results.filter(r => r.success).length;
|
|
92
|
+
const failed = results.filter(r => !r.success).length;
|
|
93
|
+
console.log(`Done: ${success} succeeded, ${failed} failed`);
|
|
94
|
+
if (failed > 0) {
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA4D5D"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hq modules update command (US-008)
|
|
3
|
+
* Updates lock for specific module
|
|
4
|
+
*/
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import { findHqRoot, readManifest, readLock, writeLock, getModulesDir } from '../utils/manifest.js';
|
|
7
|
+
import { fetchRepo, pullRepo, getCurrentCommit, isRepo } from '../utils/git.js';
|
|
8
|
+
export function registerUpdateCommand(program) {
|
|
9
|
+
program
|
|
10
|
+
.command('update [module-name]')
|
|
11
|
+
.description('Update lock for a specific module (or all if no name given)')
|
|
12
|
+
.action(async (moduleName) => {
|
|
13
|
+
try {
|
|
14
|
+
const hqRoot = findHqRoot();
|
|
15
|
+
const manifest = readManifest(hqRoot);
|
|
16
|
+
if (!manifest || manifest.modules.length === 0) {
|
|
17
|
+
console.log('No modules in manifest.');
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
let lock = readLock(hqRoot);
|
|
21
|
+
if (!lock) {
|
|
22
|
+
lock = { version: '1', locked: {} };
|
|
23
|
+
}
|
|
24
|
+
const modulesDir = getModulesDir(hqRoot);
|
|
25
|
+
const modulesToUpdate = moduleName
|
|
26
|
+
? manifest.modules.filter(m => m.name === moduleName)
|
|
27
|
+
: manifest.modules;
|
|
28
|
+
if (moduleName && modulesToUpdate.length === 0) {
|
|
29
|
+
console.error(`Module "${moduleName}" not found in manifest.`);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
for (const module of modulesToUpdate) {
|
|
33
|
+
const moduleDir = path.join(modulesDir, module.name);
|
|
34
|
+
if (!await isRepo(moduleDir)) {
|
|
35
|
+
console.log(` ${module.name}: not installed, skipping`);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
console.log(` ${module.name}: fetching...`);
|
|
39
|
+
await fetchRepo(moduleDir);
|
|
40
|
+
await pullRepo(moduleDir);
|
|
41
|
+
const commit = await getCurrentCommit(moduleDir);
|
|
42
|
+
const oldCommit = lock.locked[module.name];
|
|
43
|
+
lock.locked[module.name] = commit;
|
|
44
|
+
if (oldCommit === commit) {
|
|
45
|
+
console.log(` ${module.name}: already up to date @ ${commit.slice(0, 7)}`);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
console.log(` ${module.name}: updated ${oldCommit?.slice(0, 7) || 'none'} -> ${commit.slice(0, 7)}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
writeLock(hqRoot, lock);
|
|
52
|
+
console.log('\nLock file updated.');
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;GAEG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* HQ CLI - Module management and cloud sync for HQ
|
|
4
|
+
*/
|
|
5
|
+
import { Command } from "commander";
|
|
6
|
+
import { registerAddCommand } from "./commands/add.js";
|
|
7
|
+
import { registerSyncCommand } from "./commands/sync.js";
|
|
8
|
+
import { registerListCommand } from "./commands/list.js";
|
|
9
|
+
import { registerUpdateCommand } from "./commands/update.js";
|
|
10
|
+
import { registerCloudCommands } from "./commands/cloud.js";
|
|
11
|
+
import { registerAuthCommand } from "./commands/auth.js";
|
|
12
|
+
import { registerCloudSetupCommand } from "./commands/cloud-setup.js";
|
|
13
|
+
const program = new Command();
|
|
14
|
+
program
|
|
15
|
+
.name("hq")
|
|
16
|
+
.description("HQ management CLI — modules and cloud sync")
|
|
17
|
+
.version("5.1.0");
|
|
18
|
+
// Module management subcommand group
|
|
19
|
+
const modulesCmd = program
|
|
20
|
+
.command("modules")
|
|
21
|
+
.description("Module management commands");
|
|
22
|
+
registerAddCommand(modulesCmd);
|
|
23
|
+
registerSyncCommand(modulesCmd);
|
|
24
|
+
registerListCommand(modulesCmd);
|
|
25
|
+
registerUpdateCommand(modulesCmd);
|
|
26
|
+
// Cloud sync subcommand group
|
|
27
|
+
const syncCmd = program
|
|
28
|
+
.command("sync")
|
|
29
|
+
.description("Cloud sync commands — sync HQ files via API proxy");
|
|
30
|
+
registerCloudCommands(syncCmd);
|
|
31
|
+
// Authentication commands (hq auth login|logout|status)
|
|
32
|
+
registerAuthCommand(program);
|
|
33
|
+
// Cloud session management (hq cloud setup-token|status)
|
|
34
|
+
registerCloudSetupCommand(program);
|
|
35
|
+
program.parse();
|
|
36
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAEtE,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,IAAI,CAAC;KACV,WAAW,CAAC,4CAA4C,CAAC;KACzD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,qCAAqC;AACrC,MAAM,UAAU,GAAG,OAAO;KACvB,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CAAC,4BAA4B,CAAC,CAAC;AAE7C,kBAAkB,CAAC,UAAU,CAAC,CAAC;AAC/B,mBAAmB,CAAC,UAAU,CAAC,CAAC;AAChC,mBAAmB,CAAC,UAAU,CAAC,CAAC;AAChC,qBAAqB,CAAC,UAAU,CAAC,CAAC;AAElC,8BAA8B;AAC9B,MAAM,OAAO,GAAG,OAAO;KACpB,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,mDAAmD,CAAC,CAAC;AAEpE,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAE/B,wDAAwD;AACxD,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAE7B,yDAAyD;AACzD,yBAAyB,CAAC,OAAO,CAAC,CAAC;AAEnC,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Link Sync Strategy (US-006)
|
|
3
|
+
* Symlinks module paths into HQ tree
|
|
4
|
+
*/
|
|
5
|
+
import type { ModuleDefinition, SyncResult } from '../types.js';
|
|
6
|
+
export declare function linkSync(module: ModuleDefinition, moduleDir: string, hqRoot: string): Promise<SyncResult>;
|
|
7
|
+
//# sourceMappingURL=link.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../src/strategies/link.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEhE,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,gBAAgB,EACxB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,CAAC,CAgDrB"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Link Sync Strategy (US-006)
|
|
3
|
+
* Symlinks module paths into HQ tree
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
export async function linkSync(module, moduleDir, hqRoot) {
|
|
8
|
+
let filesChanged = 0;
|
|
9
|
+
for (const mapping of module.paths) {
|
|
10
|
+
const srcPath = path.join(moduleDir, mapping.src);
|
|
11
|
+
const destPath = path.join(hqRoot, mapping.dest);
|
|
12
|
+
// Validate source exists
|
|
13
|
+
if (!fs.existsSync(srcPath)) {
|
|
14
|
+
return {
|
|
15
|
+
module: module.name,
|
|
16
|
+
success: false,
|
|
17
|
+
action: 'skipped',
|
|
18
|
+
message: `Source path not found: ${mapping.src}`,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
// Ensure dest parent directory exists
|
|
22
|
+
const destDir = path.dirname(destPath);
|
|
23
|
+
if (!fs.existsSync(destDir)) {
|
|
24
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
// Handle existing dest
|
|
27
|
+
if (fs.existsSync(destPath)) {
|
|
28
|
+
const stat = fs.lstatSync(destPath);
|
|
29
|
+
if (stat.isSymbolicLink()) {
|
|
30
|
+
// Remove existing symlink and recreate
|
|
31
|
+
fs.unlinkSync(destPath);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
// Real file exists - warn and skip
|
|
35
|
+
console.warn(` Warning: Real file exists at ${mapping.dest}, skipping`);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Create relative symlink for portability
|
|
40
|
+
const relativeSrc = path.relative(destDir, srcPath);
|
|
41
|
+
fs.symlinkSync(relativeSrc, destPath);
|
|
42
|
+
filesChanged++;
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
module: module.name,
|
|
46
|
+
success: true,
|
|
47
|
+
action: 'synced',
|
|
48
|
+
filesChanged,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link.js","sourceRoot":"","sources":["../../src/strategies/link.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,MAAwB,EACxB,SAAiB,EACjB,MAAc;IAEd,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;QAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QAEjD,yBAAyB;QACzB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,OAAO;gBACL,MAAM,EAAE,MAAM,CAAC,IAAI;gBACnB,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,SAAS;gBACjB,OAAO,EAAE,0BAA0B,OAAO,CAAC,GAAG,EAAE;aACjD,CAAC;QACJ,CAAC;QAED,sCAAsC;QACtC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACvC,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;QAED,uBAAuB;QACvB,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YACpC,IAAI,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;gBAC1B,uCAAuC;gBACvC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YAC1B,CAAC;iBAAM,CAAC;gBACN,mCAAmC;gBACnC,OAAO,CAAC,IAAI,CAAC,kCAAkC,OAAO,CAAC,IAAI,YAAY,CAAC,CAAC;gBACzE,SAAS;YACX,CAAC;QACH,CAAC;QAED,0CAA0C;QAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACpD,EAAE,CAAC,WAAW,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QACtC,YAAY,EAAE,CAAC;IACjB,CAAC;IAED,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,IAAI;QACnB,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,QAAQ;QAChB,YAAY;KACb,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge Sync Strategy (US-007)
|
|
3
|
+
* Copies files from module into HQ, tracks state for conflict detection
|
|
4
|
+
*/
|
|
5
|
+
import type { ModuleDefinition, SyncResult } from '../types.js';
|
|
6
|
+
export declare function mergeSync(module: ModuleDefinition, moduleDir: string, hqRoot: string): Promise<SyncResult>;
|
|
7
|
+
//# sourceMappingURL=merge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../../src/strategies/merge.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAa,MAAM,aAAa,CAAC;AA8D3E,wBAAsB,SAAS,CAC7B,MAAM,EAAE,gBAAgB,EACxB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,CAAC,CAmErB"}
|