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,127 @@
1
+ /**
2
+ * Path validation module.
3
+ *
4
+ * Validates and canonicalises project paths to prevent path traversal
5
+ * attacks and restrict operations to safe directories (within $HOME
6
+ * or explicitly approved locations).
7
+ *
8
+ * @module core/path-validator
9
+ */
10
+ import * as fs from 'node:fs';
11
+ import * as path from 'node:path';
12
+ import * as os from 'node:os';
13
+ /**
14
+ * Blocked directory prefixes that are never valid project paths.
15
+ * These are system directories that should never be tracked.
16
+ */
17
+ const BLOCKED_PREFIXES = [
18
+ '/etc',
19
+ '/usr',
20
+ '/bin',
21
+ '/sbin',
22
+ '/var',
23
+ '/sys',
24
+ '/proc',
25
+ '/dev',
26
+ '/boot',
27
+ '/lib',
28
+ '/lib64',
29
+ '/root',
30
+ ];
31
+ /**
32
+ * Canonicalise a path string.
33
+ *
34
+ * Resolves `~` to the home directory, normalises `.` and `..` segments,
35
+ * and returns an absolute path. Does NOT follow symlinks — use
36
+ * `fs.realpathSync` separately if you need the real path.
37
+ *
38
+ * @param p - The path to canonicalise (may contain `~`).
39
+ * @returns The resolved absolute path.
40
+ */
41
+ export function canonicalize(p) {
42
+ if (!p || p.trim().length === 0) {
43
+ throw new Error('Path cannot be empty.');
44
+ }
45
+ let resolved = p.trim();
46
+ // Resolve ~ to home directory (respects CTX_SYNC_HOME for testing)
47
+ const homeDir = process.env['CTX_SYNC_HOME'] ?? os.homedir();
48
+ if (resolved === '~') {
49
+ resolved = homeDir;
50
+ }
51
+ else if (resolved.startsWith('~/')) {
52
+ resolved = path.join(homeDir, resolved.slice(2));
53
+ }
54
+ // Resolve to absolute path (normalises .. and .)
55
+ resolved = path.resolve(resolved);
56
+ return resolved;
57
+ }
58
+ /**
59
+ * Validate that a project path is safe to use.
60
+ *
61
+ * A path is valid if ALL of the following are true:
62
+ * - It is non-empty and resolves to an absolute path.
63
+ * - After canonicalisation, it is within the user's home directory.
64
+ * - It does not land inside a blocked system directory.
65
+ * - If the path exists and is a symlink, the symlink target is also
66
+ * within the home directory.
67
+ *
68
+ * @param p - The path to validate (may contain `~`).
69
+ * @returns The canonicalised, validated absolute path.
70
+ * @throws If the path is outside the home directory, in a blocked
71
+ * directory, or a symlink pointing outside the home directory.
72
+ */
73
+ export function validateProjectPath(p) {
74
+ const homeDir = process.env['CTX_SYNC_HOME'] ?? os.homedir();
75
+ const resolved = canonicalize(p);
76
+ // Must be within home directory (checked first — paths inside the
77
+ // effective home are allowed even if they happen to sit under a
78
+ // system prefix, e.g. during tests on macOS where $TMPDIR is /var/…).
79
+ const isWithinHome = resolved.startsWith(homeDir + '/') || resolved === homeDir;
80
+ if (!isWithinHome) {
81
+ // Provide a more specific error for known system directories
82
+ for (const blocked of BLOCKED_PREFIXES) {
83
+ if (resolved === blocked || resolved.startsWith(blocked + '/')) {
84
+ throw new Error(`Path must be within home directory. Blocked path: ${resolved}\n` +
85
+ `System directories like ${blocked}/ are not allowed.`);
86
+ }
87
+ }
88
+ throw new Error(`Path must be within home directory.\n` +
89
+ ` Path: ${resolved}\n` +
90
+ ` Home: ${homeDir}\n` +
91
+ `Only paths under your home directory are allowed.`);
92
+ }
93
+ // If the path exists, check for symlinks pointing outside home
94
+ if (fs.existsSync(resolved)) {
95
+ const stats = fs.lstatSync(resolved);
96
+ if (stats.isSymbolicLink()) {
97
+ let realTarget;
98
+ try {
99
+ realTarget = fs.realpathSync(resolved);
100
+ }
101
+ catch {
102
+ throw new Error(`Cannot resolve symlink: ${resolved}\n` +
103
+ 'Symlinks must point to a valid location within the home directory.');
104
+ }
105
+ // Compare using the real home path too (on macOS /var → /private/var)
106
+ let realHome;
107
+ try {
108
+ realHome = fs.realpathSync(homeDir);
109
+ }
110
+ catch {
111
+ realHome = homeDir;
112
+ }
113
+ const targetInHome = realTarget.startsWith(homeDir + '/') ||
114
+ realTarget === homeDir ||
115
+ realTarget.startsWith(realHome + '/') ||
116
+ realTarget === realHome;
117
+ if (!targetInHome) {
118
+ throw new Error(`Symlink target outside allowed directory.\n` +
119
+ ` Symlink: ${resolved}\n` +
120
+ ` Target: ${realTarget}\n` +
121
+ `Symlinks must point to a location within the home directory.`);
122
+ }
123
+ }
124
+ }
125
+ return resolved;
126
+ }
127
+ //# sourceMappingURL=path-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-validator.js","sourceRoot":"","sources":["../../src/core/path-validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Recipients store module.
3
+ *
4
+ * Manages the list of team members (recipients) who can decrypt
5
+ * encrypted state files. The recipients configuration is stored
6
+ * locally in the config directory and is NEVER synced to Git.
7
+ *
8
+ * When multiple recipients are configured, all state files are
9
+ * encrypted for all recipients simultaneously using Age's
10
+ * multi-recipient support.
11
+ *
12
+ * @module core/recipients
13
+ */
14
+ import type { TeamMember, RecipientsConfig } from '@ctx-sync/shared';
15
+ /** Recipients config file name (stored in config dir, never synced) */
16
+ export declare const RECIPIENTS_FILE = "recipients.json";
17
+ /**
18
+ * Compute a fingerprint for an Age public key.
19
+ *
20
+ * Uses SHA-256 and formats as colon-separated hex pairs (e.g. A3:F2:9C:...).
21
+ * This is used for out-of-band key verification.
22
+ *
23
+ * @param publicKey - An Age public key (age1...).
24
+ * @returns A colon-separated hex fingerprint string.
25
+ */
26
+ export declare function computeFingerprint(publicKey: string): string;
27
+ /**
28
+ * Read the recipients configuration from the config directory.
29
+ *
30
+ * @param configDir - The config directory path (e.g. ~/.config/ctx-sync).
31
+ * @returns The recipients configuration, or `null` if the file does not exist.
32
+ */
33
+ export declare function getRecipients(configDir: string): RecipientsConfig | null;
34
+ /**
35
+ * Save the recipients configuration to the config directory.
36
+ *
37
+ * @param configDir - The config directory path.
38
+ * @param config - The recipients configuration to save.
39
+ */
40
+ export declare function saveRecipients(configDir: string, config: RecipientsConfig): void;
41
+ /**
42
+ * Initialize the recipients configuration with the owner's public key.
43
+ *
44
+ * Creates the recipients file if it does not exist, setting the owner
45
+ * as the sole recipient.
46
+ *
47
+ * @param configDir - The config directory path.
48
+ * @param ownerPublicKey - The owner's Age public key (age1...).
49
+ * @returns The initialised recipients configuration.
50
+ */
51
+ export declare function initRecipients(configDir: string, ownerPublicKey: string): RecipientsConfig;
52
+ /**
53
+ * Get all public keys that should be used for encryption.
54
+ *
55
+ * Returns the owner's key plus all team member keys. If no recipients
56
+ * config exists, returns only the provided owner key.
57
+ *
58
+ * @param configDir - The config directory path.
59
+ * @param ownerPublicKey - The owner's Age public key (fallback if no config).
60
+ * @returns Array of all recipient public keys.
61
+ */
62
+ export declare function getAllRecipientKeys(configDir: string, ownerPublicKey: string): string[];
63
+ /**
64
+ * Add a team member to the recipients list.
65
+ *
66
+ * @param configDir - The config directory path.
67
+ * @param name - A human-readable name for the team member.
68
+ * @param publicKey - The member's Age public key (age1...).
69
+ * @returns The added team member object.
70
+ * @throws If the public key is already in the recipients list.
71
+ * @throws If the public key format is invalid.
72
+ */
73
+ export declare function addRecipient(configDir: string, name: string, publicKey: string): TeamMember;
74
+ /**
75
+ * Remove a team member by name.
76
+ *
77
+ * @param configDir - The config directory path.
78
+ * @param name - The name of the team member to remove.
79
+ * @returns The removed team member object.
80
+ * @throws If no member with the given name exists.
81
+ */
82
+ export declare function removeRecipientByName(configDir: string, name: string): TeamMember;
83
+ /**
84
+ * Remove a team member by public key (revoke).
85
+ *
86
+ * @param configDir - The config directory path.
87
+ * @param publicKey - The Age public key of the member to revoke.
88
+ * @returns The removed team member object.
89
+ * @throws If no member with the given key exists.
90
+ */
91
+ export declare function removeRecipientByKey(configDir: string, publicKey: string): TeamMember;
92
+ /**
93
+ * List all team members.
94
+ *
95
+ * @param configDir - The config directory path.
96
+ * @returns Array of team members (empty if no recipients config or no members).
97
+ */
98
+ export declare function listRecipients(configDir: string): TeamMember[];
99
+ //# sourceMappingURL=recipients.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recipients.d.ts","sourceRoot":"","sources":["../../src/core/recipients.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAErE,uEAAuE;AACvE,eAAO,MAAM,eAAe,oBAAoB,CAAC;AAEjD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAK5D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAcxE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,gBAAgB,GACvB,IAAI,CAGN;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,GACrB,gBAAgB,CAalB;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,GACrB,MAAM,EAAE,CAaV;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB,UAAU,CAoDZ;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,GACX,UAAU,CAqBZ;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,UAAU,CAmBZ;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,EAAE,CAM9D"}
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Recipients store module.
3
+ *
4
+ * Manages the list of team members (recipients) who can decrypt
5
+ * encrypted state files. The recipients configuration is stored
6
+ * locally in the config directory and is NEVER synced to Git.
7
+ *
8
+ * When multiple recipients are configured, all state files are
9
+ * encrypted for all recipients simultaneously using Age's
10
+ * multi-recipient support.
11
+ *
12
+ * @module core/recipients
13
+ */
14
+ import * as fs from 'node:fs';
15
+ import * as path from 'node:path';
16
+ import * as crypto from 'node:crypto';
17
+ /** Recipients config file name (stored in config dir, never synced) */
18
+ export const RECIPIENTS_FILE = 'recipients.json';
19
+ /**
20
+ * Compute a fingerprint for an Age public key.
21
+ *
22
+ * Uses SHA-256 and formats as colon-separated hex pairs (e.g. A3:F2:9C:...).
23
+ * This is used for out-of-band key verification.
24
+ *
25
+ * @param publicKey - An Age public key (age1...).
26
+ * @returns A colon-separated hex fingerprint string.
27
+ */
28
+ export function computeFingerprint(publicKey) {
29
+ const hash = crypto.createHash('sha256').update(publicKey).digest('hex');
30
+ // Format as colon-separated pairs: A3:F2:9C:...
31
+ const pairs = hash.substring(0, 32).match(/.{2}/g) ?? [];
32
+ return pairs.join(':').toUpperCase();
33
+ }
34
+ /**
35
+ * Read the recipients configuration from the config directory.
36
+ *
37
+ * @param configDir - The config directory path (e.g. ~/.config/ctx-sync).
38
+ * @returns The recipients configuration, or `null` if the file does not exist.
39
+ */
40
+ export function getRecipients(configDir) {
41
+ const filePath = path.join(configDir, RECIPIENTS_FILE);
42
+ if (!fs.existsSync(filePath)) {
43
+ return null;
44
+ }
45
+ const content = fs.readFileSync(filePath, 'utf-8');
46
+ if (!content.trim()) {
47
+ return null;
48
+ }
49
+ return JSON.parse(content);
50
+ }
51
+ /**
52
+ * Save the recipients configuration to the config directory.
53
+ *
54
+ * @param configDir - The config directory path.
55
+ * @param config - The recipients configuration to save.
56
+ */
57
+ export function saveRecipients(configDir, config) {
58
+ const filePath = path.join(configDir, RECIPIENTS_FILE);
59
+ fs.writeFileSync(filePath, JSON.stringify(config, null, 2), 'utf-8');
60
+ }
61
+ /**
62
+ * Initialize the recipients configuration with the owner's public key.
63
+ *
64
+ * Creates the recipients file if it does not exist, setting the owner
65
+ * as the sole recipient.
66
+ *
67
+ * @param configDir - The config directory path.
68
+ * @param ownerPublicKey - The owner's Age public key (age1...).
69
+ * @returns The initialised recipients configuration.
70
+ */
71
+ export function initRecipients(configDir, ownerPublicKey) {
72
+ const existing = getRecipients(configDir);
73
+ if (existing) {
74
+ return existing;
75
+ }
76
+ const config = {
77
+ ownerPublicKey,
78
+ members: [],
79
+ };
80
+ saveRecipients(configDir, config);
81
+ return config;
82
+ }
83
+ /**
84
+ * Get all public keys that should be used for encryption.
85
+ *
86
+ * Returns the owner's key plus all team member keys. If no recipients
87
+ * config exists, returns only the provided owner key.
88
+ *
89
+ * @param configDir - The config directory path.
90
+ * @param ownerPublicKey - The owner's Age public key (fallback if no config).
91
+ * @returns Array of all recipient public keys.
92
+ */
93
+ export function getAllRecipientKeys(configDir, ownerPublicKey) {
94
+ const config = getRecipients(configDir);
95
+ if (!config) {
96
+ return [ownerPublicKey];
97
+ }
98
+ const keys = [config.ownerPublicKey];
99
+ for (const member of config.members) {
100
+ keys.push(member.publicKey);
101
+ }
102
+ return keys;
103
+ }
104
+ /**
105
+ * Add a team member to the recipients list.
106
+ *
107
+ * @param configDir - The config directory path.
108
+ * @param name - A human-readable name for the team member.
109
+ * @param publicKey - The member's Age public key (age1...).
110
+ * @returns The added team member object.
111
+ * @throws If the public key is already in the recipients list.
112
+ * @throws If the public key format is invalid.
113
+ */
114
+ export function addRecipient(configDir, name, publicKey) {
115
+ // Validate key format
116
+ if (!publicKey.startsWith('age1')) {
117
+ throw new Error(`Invalid Age public key format. Expected key starting with "age1", got: ${publicKey.substring(0, 10)}...`);
118
+ }
119
+ const config = getRecipients(configDir);
120
+ if (!config) {
121
+ throw new Error('Recipients configuration not initialised. Run `ctx-sync init` first.');
122
+ }
123
+ // Check for duplicate key
124
+ if (config.ownerPublicKey === publicKey) {
125
+ throw new Error('Cannot add your own key as a team member.');
126
+ }
127
+ const existingMember = config.members.find((m) => m.publicKey === publicKey);
128
+ if (existingMember) {
129
+ throw new Error(`Public key already registered for team member "${existingMember.name}".`);
130
+ }
131
+ // Check for duplicate name
132
+ const existingName = config.members.find((m) => m.name.toLowerCase() === name.toLowerCase());
133
+ if (existingName) {
134
+ throw new Error(`Team member with name "${name}" already exists. Use a unique name.`);
135
+ }
136
+ const fingerprint = computeFingerprint(publicKey);
137
+ const member = {
138
+ name,
139
+ publicKey,
140
+ addedAt: new Date().toISOString(),
141
+ fingerprint,
142
+ };
143
+ config.members.push(member);
144
+ saveRecipients(configDir, config);
145
+ return member;
146
+ }
147
+ /**
148
+ * Remove a team member by name.
149
+ *
150
+ * @param configDir - The config directory path.
151
+ * @param name - The name of the team member to remove.
152
+ * @returns The removed team member object.
153
+ * @throws If no member with the given name exists.
154
+ */
155
+ export function removeRecipientByName(configDir, name) {
156
+ const config = getRecipients(configDir);
157
+ if (!config) {
158
+ throw new Error('Recipients configuration not initialised. Run `ctx-sync init` first.');
159
+ }
160
+ const index = config.members.findIndex((m) => m.name.toLowerCase() === name.toLowerCase());
161
+ if (index === -1) {
162
+ throw new Error(`No team member found with name "${name}".`);
163
+ }
164
+ const removed = config.members[index];
165
+ config.members.splice(index, 1);
166
+ saveRecipients(configDir, config);
167
+ // Safe: index was validated above so removed is always defined
168
+ return removed;
169
+ }
170
+ /**
171
+ * Remove a team member by public key (revoke).
172
+ *
173
+ * @param configDir - The config directory path.
174
+ * @param publicKey - The Age public key of the member to revoke.
175
+ * @returns The removed team member object.
176
+ * @throws If no member with the given key exists.
177
+ */
178
+ export function removeRecipientByKey(configDir, publicKey) {
179
+ const config = getRecipients(configDir);
180
+ if (!config) {
181
+ throw new Error('Recipients configuration not initialised. Run `ctx-sync init` first.');
182
+ }
183
+ const index = config.members.findIndex((m) => m.publicKey === publicKey);
184
+ if (index === -1) {
185
+ throw new Error(`No team member found with public key "${publicKey}".`);
186
+ }
187
+ const removed = config.members[index];
188
+ config.members.splice(index, 1);
189
+ saveRecipients(configDir, config);
190
+ // Safe: index was validated above so removed is always defined
191
+ return removed;
192
+ }
193
+ /**
194
+ * List all team members.
195
+ *
196
+ * @param configDir - The config directory path.
197
+ * @returns Array of team members (empty if no recipients config or no members).
198
+ */
199
+ export function listRecipients(configDir) {
200
+ const config = getRecipients(configDir);
201
+ if (!config) {
202
+ return [];
203
+ }
204
+ return config.members;
205
+ }
206
+ //# sourceMappingURL=recipients.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recipients.js","sourceRoot":"","sources":["../../src/core/recipients.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Services handler module.
3
+ *
4
+ * Manages running-service state: dev servers, background processes,
5
+ * and any port-bound services associated with a project. Services are
6
+ * persisted in `services.age` (encrypted) and restored via the command
7
+ * approval workflow — no command is ever auto-executed.
8
+ *
9
+ * @module core/services-handler
10
+ */
11
+ import type { Service, ServiceState } from '@ctx-sync/shared';
12
+ /**
13
+ * Create a new `Service` entry.
14
+ *
15
+ * @param project - The project name this service belongs to.
16
+ * @param name - Human-readable service name (e.g. "api-server").
17
+ * @param port - Port the service listens on.
18
+ * @param command - Shell command to start the service.
19
+ * @param autoStart - Whether the service should be suggested on restore.
20
+ * @returns A typed `Service` object.
21
+ */
22
+ export declare function createService(project: string, name: string, port: number, command: string, autoStart?: boolean): Service;
23
+ /**
24
+ * Validate a service entry.
25
+ *
26
+ * Checks:
27
+ * - name is non-empty
28
+ * - port is a positive integer in range 1–65535
29
+ * - command is non-empty
30
+ *
31
+ * @returns An array of human-readable error strings (empty = valid).
32
+ */
33
+ export declare function validateService(service: Service): string[];
34
+ /**
35
+ * Load all services from encrypted state.
36
+ *
37
+ * @param syncDir - The sync directory (e.g. ~/.context-sync).
38
+ * @param privateKey - Age private key for decryption.
39
+ * @returns The decrypted `ServiceState`, or an empty state if the file
40
+ * does not exist.
41
+ */
42
+ export declare function loadServices(syncDir: string, privateKey: string): Promise<ServiceState>;
43
+ /**
44
+ * Load services for a specific project.
45
+ *
46
+ * @param syncDir - The sync directory.
47
+ * @param privateKey - Age private key.
48
+ * @param project - Project name to filter by.
49
+ * @returns Array of services belonging to the project (may be empty).
50
+ */
51
+ export declare function loadProjectServices(syncDir: string, privateKey: string, project: string): Promise<Service[]>;
52
+ /**
53
+ * Save (overwrite) the entire services state.
54
+ *
55
+ * @param syncDir - The sync directory.
56
+ * @param state - The complete `ServiceState` to persist.
57
+ * @param publicKey - Age public key for encryption.
58
+ */
59
+ export declare function saveServices(syncDir: string, state: ServiceState, publicKey: string): Promise<void>;
60
+ /**
61
+ * Add a service to the encrypted state.
62
+ *
63
+ * If a service with the same project + name already exists, it is
64
+ * replaced (upsert semantics).
65
+ *
66
+ * @param syncDir - The sync directory.
67
+ * @param service - The service to add/replace.
68
+ * @param publicKey - Age public key for encryption.
69
+ * @param privateKey - Age private key for decryption (needed to read existing state).
70
+ */
71
+ export declare function addService(syncDir: string, service: Service, publicKey: string, privateKey: string): Promise<void>;
72
+ /**
73
+ * Remove a service by project + name.
74
+ *
75
+ * @param syncDir - The sync directory.
76
+ * @param project - Project name.
77
+ * @param name - Service name.
78
+ * @param publicKey - Age public key for encryption.
79
+ * @param privateKey - Age private key for decryption.
80
+ * @returns `true` if a service was removed, `false` if it was not found.
81
+ */
82
+ export declare function removeService(syncDir: string, project: string, name: string, publicKey: string, privateKey: string): Promise<boolean>;
83
+ /**
84
+ * Remove all services for a project.
85
+ *
86
+ * @param syncDir - The sync directory.
87
+ * @param project - Project name.
88
+ * @param publicKey - Age public key for encryption.
89
+ * @param privateKey - Age private key for decryption.
90
+ * @returns Number of services removed.
91
+ */
92
+ export declare function removeProjectServices(syncDir: string, project: string, publicKey: string, privateKey: string): Promise<number>;
93
+ /**
94
+ * List unique project names that have services.
95
+ *
96
+ * @param syncDir - The sync directory.
97
+ * @param privateKey - Age private key.
98
+ * @returns Sorted array of project names.
99
+ */
100
+ export declare function listServiceProjects(syncDir: string, privateKey: string): Promise<string[]>;
101
+ /**
102
+ * Get services that are marked as auto-start for a project.
103
+ *
104
+ * These are the services that `ctx-sync restore` or
105
+ * `ctx-sync service start` should suggest starting.
106
+ *
107
+ * @param syncDir - The sync directory.
108
+ * @param privateKey - Age private key.
109
+ * @param project - Project name.
110
+ * @returns Services marked with `autoStart: true`.
111
+ */
112
+ export declare function getAutoStartServices(syncDir: string, privateKey: string, project: string): Promise<Service[]>;
113
+ //# sourceMappingURL=services-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"services-handler.d.ts","sourceRoot":"","sources":["../../src/core/services-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAc9D;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,SAAS,UAAQ,GAChB,OAAO,CAET;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,EAAE,CAoB1D;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,CAAC,CAGvB;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,EAAE,CAAC,CAGpB;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC,CAalB;AAED;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAWjB;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,EAAE,CAAC,CAInB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,EAAE,CAAC,CAGpB"}