ctx-sync 1.0.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 (145) hide show
  1. package/dist/commands/audit.d.ts +76 -0
  2. package/dist/commands/audit.d.ts.map +1 -0
  3. package/dist/commands/audit.js +367 -0
  4. package/dist/commands/audit.js.map +1 -0
  5. package/dist/commands/config.d.ts +58 -0
  6. package/dist/commands/config.d.ts.map +1 -0
  7. package/dist/commands/config.js +114 -0
  8. package/dist/commands/config.js.map +1 -0
  9. package/dist/commands/dir.d.ts +56 -0
  10. package/dist/commands/dir.d.ts.map +1 -0
  11. package/dist/commands/dir.js +172 -0
  12. package/dist/commands/dir.js.map +1 -0
  13. package/dist/commands/docker.d.ts +140 -0
  14. package/dist/commands/docker.d.ts.map +1 -0
  15. package/dist/commands/docker.js +380 -0
  16. package/dist/commands/docker.js.map +1 -0
  17. package/dist/commands/env.d.ts +96 -0
  18. package/dist/commands/env.d.ts.map +1 -0
  19. package/dist/commands/env.js +352 -0
  20. package/dist/commands/env.js.map +1 -0
  21. package/dist/commands/init.d.ts +89 -0
  22. package/dist/commands/init.d.ts.map +1 -0
  23. package/dist/commands/init.js +272 -0
  24. package/dist/commands/init.js.map +1 -0
  25. package/dist/commands/key.d.ts +92 -0
  26. package/dist/commands/key.d.ts.map +1 -0
  27. package/dist/commands/key.js +274 -0
  28. package/dist/commands/key.js.map +1 -0
  29. package/dist/commands/list.d.ts +38 -0
  30. package/dist/commands/list.d.ts.map +1 -0
  31. package/dist/commands/list.js +84 -0
  32. package/dist/commands/list.js.map +1 -0
  33. package/dist/commands/note.d.ts +151 -0
  34. package/dist/commands/note.d.ts.map +1 -0
  35. package/dist/commands/note.js +411 -0
  36. package/dist/commands/note.js.map +1 -0
  37. package/dist/commands/pull.d.ts +47 -0
  38. package/dist/commands/pull.d.ts.map +1 -0
  39. package/dist/commands/pull.js +94 -0
  40. package/dist/commands/pull.js.map +1 -0
  41. package/dist/commands/push.d.ts +40 -0
  42. package/dist/commands/push.d.ts.map +1 -0
  43. package/dist/commands/push.js +94 -0
  44. package/dist/commands/push.js.map +1 -0
  45. package/dist/commands/restore.d.ts +116 -0
  46. package/dist/commands/restore.d.ts.map +1 -0
  47. package/dist/commands/restore.js +336 -0
  48. package/dist/commands/restore.js.map +1 -0
  49. package/dist/commands/service.d.ts +83 -0
  50. package/dist/commands/service.d.ts.map +1 -0
  51. package/dist/commands/service.js +259 -0
  52. package/dist/commands/service.js.map +1 -0
  53. package/dist/commands/show.d.ts +63 -0
  54. package/dist/commands/show.d.ts.map +1 -0
  55. package/dist/commands/show.js +243 -0
  56. package/dist/commands/show.js.map +1 -0
  57. package/dist/commands/status.d.ts +53 -0
  58. package/dist/commands/status.d.ts.map +1 -0
  59. package/dist/commands/status.js +150 -0
  60. package/dist/commands/status.js.map +1 -0
  61. package/dist/commands/sync.d.ts +105 -0
  62. package/dist/commands/sync.d.ts.map +1 -0
  63. package/dist/commands/sync.js +243 -0
  64. package/dist/commands/sync.js.map +1 -0
  65. package/dist/commands/team.d.ts +79 -0
  66. package/dist/commands/team.d.ts.map +1 -0
  67. package/dist/commands/team.js +233 -0
  68. package/dist/commands/team.js.map +1 -0
  69. package/dist/commands/track.d.ts +109 -0
  70. package/dist/commands/track.d.ts.map +1 -0
  71. package/dist/commands/track.js +406 -0
  72. package/dist/commands/track.js.map +1 -0
  73. package/dist/core/command-validator.d.ts +100 -0
  74. package/dist/core/command-validator.d.ts.map +1 -0
  75. package/dist/core/command-validator.js +299 -0
  76. package/dist/core/command-validator.js.map +1 -0
  77. package/dist/core/config-store.d.ts +76 -0
  78. package/dist/core/config-store.d.ts.map +1 -0
  79. package/dist/core/config-store.js +148 -0
  80. package/dist/core/config-store.js.map +1 -0
  81. package/dist/core/directories-handler.d.ts +116 -0
  82. package/dist/core/directories-handler.d.ts.map +1 -0
  83. package/dist/core/directories-handler.js +199 -0
  84. package/dist/core/directories-handler.js.map +1 -0
  85. package/dist/core/docker-handler.d.ts +183 -0
  86. package/dist/core/docker-handler.d.ts.map +1 -0
  87. package/dist/core/docker-handler.js +515 -0
  88. package/dist/core/docker-handler.js.map +1 -0
  89. package/dist/core/encryption.d.ts +79 -0
  90. package/dist/core/encryption.d.ts.map +1 -0
  91. package/dist/core/encryption.js +111 -0
  92. package/dist/core/encryption.js.map +1 -0
  93. package/dist/core/env-handler.d.ts +128 -0
  94. package/dist/core/env-handler.d.ts.map +1 -0
  95. package/dist/core/env-handler.js +272 -0
  96. package/dist/core/env-handler.js.map +1 -0
  97. package/dist/core/git-sync.d.ts +88 -0
  98. package/dist/core/git-sync.d.ts.map +1 -0
  99. package/dist/core/git-sync.js +143 -0
  100. package/dist/core/git-sync.js.map +1 -0
  101. package/dist/core/key-store.d.ts +51 -0
  102. package/dist/core/key-store.d.ts.map +1 -0
  103. package/dist/core/key-store.js +108 -0
  104. package/dist/core/key-store.js.map +1 -0
  105. package/dist/core/log-sanitizer.d.ts +72 -0
  106. package/dist/core/log-sanitizer.d.ts.map +1 -0
  107. package/dist/core/log-sanitizer.js +202 -0
  108. package/dist/core/log-sanitizer.js.map +1 -0
  109. package/dist/core/path-validator.d.ts +37 -0
  110. package/dist/core/path-validator.d.ts.map +1 -0
  111. package/dist/core/path-validator.js +127 -0
  112. package/dist/core/path-validator.js.map +1 -0
  113. package/dist/core/recipients.d.ts +99 -0
  114. package/dist/core/recipients.d.ts.map +1 -0
  115. package/dist/core/recipients.js +206 -0
  116. package/dist/core/recipients.js.map +1 -0
  117. package/dist/core/services-handler.d.ts +113 -0
  118. package/dist/core/services-handler.d.ts.map +1 -0
  119. package/dist/core/services-handler.js +176 -0
  120. package/dist/core/services-handler.js.map +1 -0
  121. package/dist/core/state-manager.d.ts +96 -0
  122. package/dist/core/state-manager.d.ts.map +1 -0
  123. package/dist/core/state-manager.js +165 -0
  124. package/dist/core/state-manager.js.map +1 -0
  125. package/dist/core/transport.d.ts +28 -0
  126. package/dist/core/transport.d.ts.map +1 -0
  127. package/dist/core/transport.js +79 -0
  128. package/dist/core/transport.js.map +1 -0
  129. package/dist/index.d.ts +20 -0
  130. package/dist/index.d.ts.map +1 -0
  131. package/dist/index.js +80 -0
  132. package/dist/index.js.map +1 -0
  133. package/dist/types/index.d.ts +5 -0
  134. package/dist/types/index.d.ts.map +1 -0
  135. package/dist/types/index.js +2 -0
  136. package/dist/types/index.js.map +1 -0
  137. package/dist/utils/errors.d.ts +81 -0
  138. package/dist/utils/errors.d.ts.map +1 -0
  139. package/dist/utils/errors.js +191 -0
  140. package/dist/utils/errors.js.map +1 -0
  141. package/dist/utils/secure-memory.d.ts +65 -0
  142. package/dist/utils/secure-memory.d.ts.map +1 -0
  143. package/dist/utils/secure-memory.js +86 -0
  144. package/dist/utils/secure-memory.js.map +1 -0
  145. package/package.json +58 -0
@@ -0,0 +1,406 @@
1
+ /**
2
+ * `ctx-sync track` command.
3
+ *
4
+ * Detects the current project's Git state, validates the path,
5
+ * encrypts the project entry, and writes it to `state.age`.
6
+ *
7
+ * Phase 16 enhancements: Step-by-step wizard with auto-detection,
8
+ * .env import, Docker tracking, mental context, and summary.
9
+ * `--yes` flag skips interactive confirmations (but NOT restore commands).
10
+ *
11
+ * @module commands/track
12
+ */
13
+ import * as fs from 'node:fs';
14
+ import * as path from 'node:path';
15
+ import * as os from 'node:os';
16
+ import * as crypto from 'node:crypto';
17
+ import { STATE_FILES } from '@ctx-sync/shared';
18
+ import { identityToRecipient } from 'age-encryption';
19
+ import { validateProjectPath } from '../core/path-validator.js';
20
+ import { loadKey } from '../core/key-store.js';
21
+ import { readState, writeState } from '../core/state-manager.js';
22
+ import { commitState } from '../core/git-sync.js';
23
+ import { getConfigDir, getSyncDir } from './init.js';
24
+ import { withErrorHandler } from '../utils/errors.js';
25
+ /**
26
+ * Detect Git information for a project directory.
27
+ *
28
+ * @param projectPath - Absolute path to the project directory.
29
+ * @returns Git metadata (branch, remote, uncommitted, stash count).
30
+ */
31
+ export async function detectGitInfo(projectPath) {
32
+ const defaultGit = {
33
+ branch: 'unknown',
34
+ remote: '',
35
+ hasUncommitted: false,
36
+ stashCount: 0,
37
+ };
38
+ const gitDir = path.join(projectPath, '.git');
39
+ if (!fs.existsSync(gitDir)) {
40
+ return defaultGit;
41
+ }
42
+ try {
43
+ const { simpleGit } = await import('simple-git');
44
+ const git = simpleGit(projectPath);
45
+ // Branch
46
+ const branchResult = await git.branch();
47
+ const branch = branchResult.current || 'unknown';
48
+ // Remote
49
+ const remotes = await git.getRemotes(true);
50
+ const origin = remotes.find((r) => r.name === 'origin');
51
+ const remote = origin?.refs?.fetch ?? '';
52
+ // Uncommitted changes
53
+ const status = await git.status();
54
+ const hasUncommitted = !status.isClean();
55
+ // Stash count
56
+ let stashCount = 0;
57
+ try {
58
+ const stashList = await git.stashList();
59
+ stashCount = stashList.total;
60
+ }
61
+ catch {
62
+ // stash list can fail on repos with no stashes — that's fine
63
+ }
64
+ return { branch, remote, hasUncommitted, stashCount };
65
+ }
66
+ catch {
67
+ return defaultGit;
68
+ }
69
+ }
70
+ /**
71
+ * Auto-detect project name from Git remote URL or directory name.
72
+ *
73
+ * Priority:
74
+ * 1. Explicit `--name` flag.
75
+ * 2. Repository name from Git remote URL (e.g., `origin`).
76
+ * 3. Directory name.
77
+ *
78
+ * @param projectPath - Absolute path to the project directory.
79
+ * @param gitRemote - The Git remote fetch URL (empty if none).
80
+ * @returns The detected project name.
81
+ */
82
+ export function detectProjectName(projectPath, gitRemote) {
83
+ // Try to extract repo name from Git remote URL
84
+ if (gitRemote) {
85
+ // SSH format: git@github.com:user/repo-name.git
86
+ const sshMatch = /\/([^/]+?)(?:\.git)?$/.exec(gitRemote);
87
+ if (sshMatch?.[1]) {
88
+ return sshMatch[1];
89
+ }
90
+ // HTTPS format: https://github.com/user/repo-name.git
91
+ const httpsMatch = /\/([^/]+?)(?:\.git)?$/.exec(gitRemote);
92
+ if (httpsMatch?.[1]) {
93
+ return httpsMatch[1];
94
+ }
95
+ }
96
+ // Fall back to directory name
97
+ return path.basename(projectPath);
98
+ }
99
+ /**
100
+ * Derive the machine ID for the current host.
101
+ *
102
+ * Uses hostname as a simple machine identifier.
103
+ * A more robust approach (hardware ID) can be added later.
104
+ */
105
+ function getMachineInfo() {
106
+ const hostname = os.hostname();
107
+ return {
108
+ id: crypto.createHash('sha256').update(hostname).digest('hex').slice(0, 16),
109
+ hostname,
110
+ };
111
+ }
112
+ /**
113
+ * Run the interactive wizard to collect user choices.
114
+ *
115
+ * @param context - Information about the detected project state.
116
+ * @returns User's wizard answers.
117
+ */
118
+ async function runWizard(context) {
119
+ const Enquirer = (await import('enquirer')).default;
120
+ const enquirer = new Enquirer();
121
+ const answers = {
122
+ importEnv: false,
123
+ trackDocker: false,
124
+ currentTask: '',
125
+ nextSteps: [],
126
+ confirmCommit: true,
127
+ };
128
+ // Step 1: Confirm or change project name (already auto-detected)
129
+ // This is shown via console output, not a prompt
130
+ // Step 2: .env import prompt
131
+ if (context.envFileFound) {
132
+ const envResponse = await enquirer.prompt({
133
+ type: 'confirm',
134
+ name: 'importEnv',
135
+ message: 'Found .env file. Import environment variables?',
136
+ initial: true,
137
+ });
138
+ const envVal = String(envResponse.importEnv ?? '');
139
+ answers.importEnv = envVal === 'true' || envVal.toLowerCase() === 'yes';
140
+ }
141
+ // Step 3: Docker tracking prompt
142
+ if (context.dockerComposeFound) {
143
+ const dockerResponse = await enquirer.prompt({
144
+ type: 'confirm',
145
+ name: 'trackDocker',
146
+ message: 'Found Docker Compose. Track Docker services?',
147
+ initial: true,
148
+ });
149
+ const dVal = String(dockerResponse.trackDocker ?? '');
150
+ answers.trackDocker = dVal === 'true' || dVal.toLowerCase() === 'yes';
151
+ }
152
+ // Step 4: Mental context — current task
153
+ const taskResponse = await enquirer.prompt({
154
+ type: 'input',
155
+ name: 'currentTask',
156
+ message: 'What are you working on? (press Enter to skip)',
157
+ });
158
+ if (taskResponse.currentTask?.trim()) {
159
+ answers.currentTask = taskResponse.currentTask.trim();
160
+ }
161
+ // Step 5: Mental context — next steps
162
+ if (answers.currentTask) {
163
+ const stepsResponse = await enquirer.prompt({
164
+ type: 'input',
165
+ name: 'nextSteps',
166
+ message: 'Next steps? (comma-separated, or press Enter to skip)',
167
+ });
168
+ if (stepsResponse.nextSteps?.trim()) {
169
+ answers.nextSteps = stepsResponse.nextSteps
170
+ .split(',')
171
+ .map((s) => s.trim())
172
+ .filter(Boolean);
173
+ }
174
+ }
175
+ // Step 6: Summary and confirmation
176
+ answers.confirmCommit = true;
177
+ return answers;
178
+ }
179
+ /**
180
+ * Execute the track command logic.
181
+ *
182
+ * 1. Resolve and validate the project path.
183
+ * 2. Auto-detect project name from Git remote / directory.
184
+ * 3. Detect Git info, .env, docker-compose.
185
+ * 4. Run interactive wizard (if not --yes or --no-interactive).
186
+ * 5. Build or update the Project entry.
187
+ * 6. Optionally import .env, track Docker, set mental context.
188
+ * 7. Encrypt and write state.age.
189
+ * 8. Optionally commit to the sync repo.
190
+ *
191
+ * @param options - Track command options.
192
+ * @returns Track result including the project entry.
193
+ */
194
+ export async function executeTrack(options) {
195
+ // 1. Resolve and validate path
196
+ const rawPath = options.path ?? process.cwd();
197
+ const projectPath = validateProjectPath(rawPath);
198
+ // 2. Load key and derive public key
199
+ const configDir = getConfigDir();
200
+ const syncDir = getSyncDir();
201
+ const privateKey = loadKey(configDir);
202
+ const publicKey = await identityToRecipient(privateKey);
203
+ // 3. Detect Git info
204
+ const gitInfo = await detectGitInfo(projectPath);
205
+ // 4. Auto-detect project name
206
+ const projectName = options.name ?? detectProjectName(projectPath, gitInfo.remote);
207
+ // 5. Check for .env and docker-compose
208
+ const envFileFound = fs.existsSync(path.join(projectPath, '.env'));
209
+ const dockerComposeFound = fs.existsSync(path.join(projectPath, 'docker-compose.yml')) ||
210
+ fs.existsSync(path.join(projectPath, 'docker-compose.yaml')) ||
211
+ fs.existsSync(path.join(projectPath, 'compose.yml')) ||
212
+ fs.existsSync(path.join(projectPath, 'compose.yaml'));
213
+ // 6. Read existing state (or create new)
214
+ const existingState = await readState(syncDir, privateKey, 'state');
215
+ const machine = getMachineInfo();
216
+ const state = existingState ?? {
217
+ machine,
218
+ projects: [],
219
+ };
220
+ // Ensure machine info is current
221
+ state.machine = machine;
222
+ // 7. Find or create project entry
223
+ const existingIndex = state.projects.findIndex((p) => p.path === projectPath);
224
+ const isNew = existingIndex === -1;
225
+ const existingProject = isNew ? undefined : state.projects[existingIndex];
226
+ const project = {
227
+ id: existingProject?.id ?? crypto.randomUUID(),
228
+ name: projectName,
229
+ path: projectPath,
230
+ git: gitInfo,
231
+ lastAccessed: new Date().toISOString(),
232
+ };
233
+ if (isNew) {
234
+ state.projects.push(project);
235
+ }
236
+ else {
237
+ state.projects[existingIndex] = project;
238
+ }
239
+ // 8. Run wizard (unless --yes or --no-interactive)
240
+ let wizardAnswers = null;
241
+ let envVarsImported = 0;
242
+ let dockerServicesTracked = 0;
243
+ let mentalContextSet = false;
244
+ const isInteractive = !options.yes && !options.noInteractive;
245
+ const autoAcceptAll = options.yes === true;
246
+ if (options.wizardPromptFn) {
247
+ // Testing override
248
+ wizardAnswers = await options.wizardPromptFn({
249
+ projectName,
250
+ projectPath,
251
+ gitBranch: gitInfo.branch,
252
+ envFileFound,
253
+ dockerComposeFound,
254
+ isNew,
255
+ });
256
+ }
257
+ else if (isInteractive && isNew) {
258
+ // Interactive wizard for new projects only
259
+ wizardAnswers = await runWizard({
260
+ projectName,
261
+ projectPath,
262
+ gitBranch: gitInfo.branch,
263
+ envFileFound,
264
+ dockerComposeFound,
265
+ isNew,
266
+ });
267
+ }
268
+ else if (autoAcceptAll) {
269
+ // --yes mode: auto-accept .env import and Docker tracking, skip mental context
270
+ wizardAnswers = {
271
+ importEnv: envFileFound,
272
+ trackDocker: dockerComposeFound,
273
+ currentTask: '',
274
+ nextSteps: [],
275
+ confirmCommit: true,
276
+ };
277
+ }
278
+ // 9. Process wizard answers — import .env
279
+ if (wizardAnswers?.importEnv && envFileFound) {
280
+ try {
281
+ const envFilePath = path.join(projectPath, '.env');
282
+ const content = fs.readFileSync(envFilePath, 'utf-8');
283
+ const { parseEnvFile, importEnvVars } = await import('../core/env-handler.js');
284
+ const vars = parseEnvFile(content);
285
+ envVarsImported = await importEnvVars(projectName, vars, syncDir, publicKey, privateKey);
286
+ }
287
+ catch {
288
+ // .env import failure is non-fatal
289
+ }
290
+ }
291
+ // 10. Process wizard answers — track Docker
292
+ if (wizardAnswers?.trackDocker && dockerComposeFound) {
293
+ try {
294
+ const { buildDockerStateEntry, saveDockerState } = await import('../core/docker-handler.js');
295
+ const entry = buildDockerStateEntry(projectName, projectPath);
296
+ if (entry) {
297
+ await saveDockerState(syncDir, projectName, entry, publicKey, privateKey);
298
+ dockerServicesTracked = entry.services.length;
299
+ }
300
+ }
301
+ catch {
302
+ // Docker tracking failure is non-fatal
303
+ }
304
+ }
305
+ // 11. Process wizard answers — set mental context
306
+ if (wizardAnswers?.currentTask) {
307
+ try {
308
+ const { mergeContext } = await import('./note.js');
309
+ const existingMentalContext = await readState(syncDir, privateKey, 'mental-context');
310
+ const mcData = existingMentalContext ?? {};
311
+ const existing = mcData[projectName] ?? null;
312
+ const merged = mergeContext(existing, {
313
+ currentTask: wizardAnswers.currentTask,
314
+ nextSteps: wizardAnswers.nextSteps,
315
+ });
316
+ mcData[projectName] = merged;
317
+ await writeState(syncDir, mcData, publicKey, 'mental-context');
318
+ mentalContextSet = true;
319
+ }
320
+ catch {
321
+ // Mental context failure is non-fatal
322
+ }
323
+ }
324
+ // 12. Write encrypted state
325
+ await writeState(syncDir, state, publicKey, 'state');
326
+ // 13. Collect all files that need committing
327
+ const filesToCommit = [STATE_FILES.STATE, STATE_FILES.MANIFEST];
328
+ if (envVarsImported > 0) {
329
+ filesToCommit.push(STATE_FILES.ENV_VARS);
330
+ }
331
+ if (dockerServicesTracked > 0) {
332
+ filesToCommit.push(STATE_FILES.DOCKER_STATE);
333
+ }
334
+ if (mentalContextSet) {
335
+ filesToCommit.push(STATE_FILES.MENTAL_CONTEXT);
336
+ }
337
+ // 14. Optionally commit
338
+ if (!options.noSync && (wizardAnswers?.confirmCommit !== false)) {
339
+ await commitState(syncDir, filesToCommit, `feat: ${isNew ? 'track' : 'update'} project ${projectName}`);
340
+ }
341
+ return {
342
+ project,
343
+ isNew,
344
+ envFileFound,
345
+ dockerComposeFound,
346
+ envVarsImported,
347
+ dockerServicesTracked,
348
+ mentalContextSet,
349
+ };
350
+ }
351
+ /**
352
+ * Register the `track` command on the given Commander program.
353
+ */
354
+ export function registerTrackCommand(program) {
355
+ program
356
+ .command('track')
357
+ .description('Track the current project directory')
358
+ .option('-n, --name <name>', 'Project name (default: auto-detect from Git remote)')
359
+ .option('-p, --path <path>', 'Project path (default: current directory)')
360
+ .option('--no-sync', 'Skip syncing to Git after tracking')
361
+ .option('-y, --yes', 'Accept all defaults without prompting')
362
+ .option('--no-interactive', 'Skip all interactive prompts')
363
+ .action(withErrorHandler(async (opts) => {
364
+ const options = {
365
+ name: opts['name'],
366
+ path: opts['path'],
367
+ noSync: opts['sync'] === false,
368
+ yes: opts['yes'],
369
+ noInteractive: opts['interactive'] === false,
370
+ };
371
+ const result = await executeTrack(options);
372
+ const chalk = (await import('chalk')).default;
373
+ if (result.isNew) {
374
+ console.log(chalk.green('✅ Tracking project: ') + result.project.name);
375
+ }
376
+ else {
377
+ console.log(chalk.green('✅ Updated project: ') + result.project.name);
378
+ }
379
+ console.log(` Path: ${result.project.path}`);
380
+ console.log(` Branch: ${result.project.git.branch}`);
381
+ if (result.project.git.hasUncommitted) {
382
+ console.log(chalk.yellow(' ⚠ Uncommitted changes detected'));
383
+ }
384
+ if (result.project.git.stashCount > 0) {
385
+ console.log(chalk.yellow(` ⚠ ${result.project.git.stashCount} stash(es)`));
386
+ }
387
+ // Wizard results
388
+ if (result.envVarsImported > 0) {
389
+ console.log(chalk.green(` ✅ Imported ${result.envVarsImported} env vars (all encrypted)`));
390
+ }
391
+ else if (result.envFileFound) {
392
+ console.log(chalk.cyan(' ℹ .env file found — use `ctx-sync env import` to track environment variables'));
393
+ }
394
+ if (result.dockerServicesTracked > 0) {
395
+ console.log(chalk.green(` ✅ Tracking ${result.dockerServicesTracked} Docker service(s)`));
396
+ }
397
+ else if (result.dockerComposeFound) {
398
+ console.log(chalk.cyan(' ℹ Docker Compose found — use `ctx-sync docker track` to track services'));
399
+ }
400
+ if (result.mentalContextSet) {
401
+ console.log(chalk.green(' ✅ Mental context saved'));
402
+ }
403
+ console.log(chalk.dim('\n State encrypted and saved to state.age'));
404
+ }));
405
+ }
406
+ //# sourceMappingURL=track.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"track.js","sourceRoot":"","sources":["../../src/commands/track.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Command validator module.
3
+ *
4
+ * Validates shell commands for suspicious patterns before execution.
5
+ * Used by the `restore` command to prevent remote code execution (RCE)
6
+ * via a compromised Git repo injecting malicious commands into the
7
+ * encrypted state.
8
+ *
9
+ * **Critical security property:** No command is ever executed without
10
+ * explicit user confirmation. There is no `--yes` or `--no-confirm`
11
+ * flag — command confirmation cannot be bypassed.
12
+ *
13
+ * @module core/command-validator
14
+ */
15
+ /** Result of command validation */
16
+ export interface ValidationResult {
17
+ /** Whether the command matches a suspicious pattern */
18
+ suspicious: boolean;
19
+ /** Human-readable reason why the command is suspicious (empty if safe) */
20
+ reason: string;
21
+ }
22
+ /** A command pending approval, with metadata for display */
23
+ export interface PendingCommand {
24
+ /** The shell command string */
25
+ command: string;
26
+ /** Display label for the command category (e.g. "Docker service", "Auto-start service") */
27
+ label: string;
28
+ /** Optional working directory */
29
+ cwd?: string;
30
+ /** Optional port */
31
+ port?: number;
32
+ /** Optional Docker image name */
33
+ image?: string;
34
+ }
35
+ /** Result of presenting commands for approval */
36
+ export interface ApprovalResult {
37
+ /** Commands that were approved */
38
+ approved: PendingCommand[];
39
+ /** Commands that were rejected */
40
+ rejected: PendingCommand[];
41
+ /** Whether all commands were skipped (non-interactive mode) */
42
+ skippedAll: boolean;
43
+ }
44
+ /**
45
+ * Validate a shell command for suspicious patterns.
46
+ *
47
+ * Checks the command string against known dangerous patterns. This is a
48
+ * defence-in-depth measure — the primary protection is the mandatory
49
+ * user confirmation before any command executes.
50
+ *
51
+ * @param cmd - The shell command string to validate.
52
+ * @returns Validation result with suspicious flag and reason.
53
+ */
54
+ export declare function validateCommand(cmd: string): ValidationResult;
55
+ /**
56
+ * Validate a Docker image name for suspicious patterns.
57
+ *
58
+ * Flags images from unofficial registries or suspicious names.
59
+ * Trusted images come from well-known publishers (e.g. `postgres`,
60
+ * `redis`, `node`) without a registry prefix, or from trusted registries
61
+ * like `docker.io`.
62
+ *
63
+ * @param image - The Docker image name (e.g. 'postgres:15', 'evil.com/malware:latest').
64
+ * @returns Validation result with warning flag and reason.
65
+ */
66
+ export declare function validateDockerImage(image: string): ValidationResult;
67
+ /**
68
+ * Format commands for display to the user before execution.
69
+ *
70
+ * Groups commands by category (Docker services, auto-start services)
71
+ * and adds warning indicators for suspicious commands.
72
+ *
73
+ * @param commands - The list of commands pending approval.
74
+ * @returns Formatted string for terminal display.
75
+ */
76
+ export declare function formatCommandsForDisplay(commands: PendingCommand[]): string;
77
+ /**
78
+ * Present commands for user approval.
79
+ *
80
+ * In interactive mode, displays commands and prompts the user to approve
81
+ * all, reject all, or select individually.
82
+ *
83
+ * In non-interactive mode, displays commands but does NOT execute any —
84
+ * this is the safe default.
85
+ *
86
+ * **Security:** There is no `--yes` or `--no-confirm` flag. Command
87
+ * confirmation cannot be bypassed programmatically.
88
+ *
89
+ * @param commands - The list of commands to present.
90
+ * @param options - Display options.
91
+ * @param options.interactive - Whether to prompt for approval (false = show only).
92
+ * @param options.promptFn - Optional override for the approval prompt (for testing).
93
+ * @returns The approval result (which commands were approved/rejected).
94
+ */
95
+ export declare function presentCommandsForApproval(commands: PendingCommand[], options?: {
96
+ interactive?: boolean;
97
+ promptFn?: (commands: PendingCommand[]) => Promise<'all' | 'none' | 'select'>;
98
+ selectFn?: (cmd: PendingCommand, index: number) => Promise<boolean>;
99
+ }): Promise<ApprovalResult>;
100
+ //# sourceMappingURL=command-validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-validator.d.ts","sourceRoot":"","sources":["../../src/core/command-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,mCAAmC;AACnC,MAAM,WAAW,gBAAgB;IAC/B,uDAAuD;IACvD,UAAU,EAAE,OAAO,CAAC;IACpB,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,4DAA4D;AAC5D,MAAM,WAAW,cAAc;IAC7B,+BAA+B;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,2FAA2F;IAC3F,KAAK,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oBAAoB;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,iDAAiD;AACjD,MAAM,WAAW,cAAc;IAC7B,kCAAkC;IAClC,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,kCAAkC;IAClC,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,+DAA+D;IAC/D,UAAU,EAAE,OAAO,CAAC;CACrB;AAiGD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAc7D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAoCnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,MAAM,CAsD3E;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,cAAc,EAAE,EAC1B,OAAO,GAAE;IACP,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,cAAc,EAAE,KAAK,OAAO,CAAC,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC,CAAC;IAC9E,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAChE,GACL,OAAO,CAAC,cAAc,CAAC,CAyDzB"}