devports 0.0.1 → 1.0.1

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 (151) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/LICENSE +21 -0
  3. package/README.md +810 -29
  4. package/dist/cli.d.ts +7 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +329 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/commands/allocate.command.d.ts +8 -0
  9. package/dist/commands/allocate.command.d.ts.map +1 -0
  10. package/dist/commands/allocate.command.js +84 -0
  11. package/dist/commands/allocate.command.js.map +1 -0
  12. package/dist/commands/base-command.d.ts +28 -0
  13. package/dist/commands/base-command.d.ts.map +1 -0
  14. package/dist/commands/base-command.js +33 -0
  15. package/dist/commands/base-command.js.map +1 -0
  16. package/dist/commands/check.command.d.ts +7 -0
  17. package/dist/commands/check.command.d.ts.map +1 -0
  18. package/dist/commands/check.command.js +44 -0
  19. package/dist/commands/check.command.js.map +1 -0
  20. package/dist/commands/completion.command.d.ts +7 -0
  21. package/dist/commands/completion.command.d.ts.map +1 -0
  22. package/dist/commands/completion.command.js +116 -0
  23. package/dist/commands/completion.command.js.map +1 -0
  24. package/dist/commands/gitignore.command.d.ts +7 -0
  25. package/dist/commands/gitignore.command.d.ts.map +1 -0
  26. package/dist/commands/gitignore.command.js +61 -0
  27. package/dist/commands/gitignore.command.js.map +1 -0
  28. package/dist/commands/index.d.ts +7 -0
  29. package/dist/commands/index.d.ts.map +1 -0
  30. package/dist/commands/index.js +35 -0
  31. package/dist/commands/index.js.map +1 -0
  32. package/dist/commands/info.command.d.ts +7 -0
  33. package/dist/commands/info.command.d.ts.map +1 -0
  34. package/dist/commands/info.command.js +40 -0
  35. package/dist/commands/info.command.js.map +1 -0
  36. package/dist/commands/list.command.d.ts +8 -0
  37. package/dist/commands/list.command.d.ts.map +1 -0
  38. package/dist/commands/list.command.js +165 -0
  39. package/dist/commands/list.command.js.map +1 -0
  40. package/dist/commands/release.command.d.ts +8 -0
  41. package/dist/commands/release.command.d.ts.map +1 -0
  42. package/dist/commands/release.command.js +89 -0
  43. package/dist/commands/release.command.js.map +1 -0
  44. package/dist/commands/render.command.d.ts +7 -0
  45. package/dist/commands/render.command.d.ts.map +1 -0
  46. package/dist/commands/render.command.js +53 -0
  47. package/dist/commands/render.command.js.map +1 -0
  48. package/dist/commands/reserve.command.d.ts +7 -0
  49. package/dist/commands/reserve.command.d.ts.map +1 -0
  50. package/dist/commands/reserve.command.js +42 -0
  51. package/dist/commands/reserve.command.js.map +1 -0
  52. package/dist/commands/setup.command.d.ts +7 -0
  53. package/dist/commands/setup.command.d.ts.map +1 -0
  54. package/dist/commands/setup.command.js +43 -0
  55. package/dist/commands/setup.command.js.map +1 -0
  56. package/dist/commands/status.command.d.ts +7 -0
  57. package/dist/commands/status.command.d.ts.map +1 -0
  58. package/dist/commands/status.command.js +41 -0
  59. package/dist/commands/status.command.js.map +1 -0
  60. package/dist/commands/unreserve.command.d.ts +7 -0
  61. package/dist/commands/unreserve.command.d.ts.map +1 -0
  62. package/dist/commands/unreserve.command.js +38 -0
  63. package/dist/commands/unreserve.command.js.map +1 -0
  64. package/dist/commands/worktree-add.command.d.ts +7 -0
  65. package/dist/commands/worktree-add.command.d.ts.map +1 -0
  66. package/dist/commands/worktree-add.command.js +68 -0
  67. package/dist/commands/worktree-add.command.js.map +1 -0
  68. package/dist/commands/worktree-remove.command.d.ts +7 -0
  69. package/dist/commands/worktree-remove.command.d.ts.map +1 -0
  70. package/dist/commands/worktree-remove.command.js +33 -0
  71. package/dist/commands/worktree-remove.command.js.map +1 -0
  72. package/dist/completion/bash-completion-template.d.ts +5 -0
  73. package/dist/completion/bash-completion-template.d.ts.map +1 -0
  74. package/dist/completion/bash-completion-template.js +14 -0
  75. package/dist/completion/bash-completion-template.js.map +1 -0
  76. package/dist/completion/bash.sh +208 -0
  77. package/dist/completion/completion-data.d.ts +16 -0
  78. package/dist/completion/completion-data.d.ts.map +1 -0
  79. package/dist/completion/completion-data.js +38 -0
  80. package/dist/completion/completion-data.js.map +1 -0
  81. package/dist/completion/index.d.ts +24 -0
  82. package/dist/completion/index.d.ts.map +1 -0
  83. package/dist/completion/index.js +30 -0
  84. package/dist/completion/index.js.map +1 -0
  85. package/dist/completion/shell-config.d.ts +27 -0
  86. package/dist/completion/shell-config.d.ts.map +1 -0
  87. package/dist/completion/shell-config.js +243 -0
  88. package/dist/completion/shell-config.js.map +1 -0
  89. package/dist/completion/zsh-completion-template.d.ts +5 -0
  90. package/dist/completion/zsh-completion-template.d.ts.map +1 -0
  91. package/dist/completion/zsh-completion-template.js +14 -0
  92. package/dist/completion/zsh-completion-template.js.map +1 -0
  93. package/dist/completion/zsh.sh +164 -0
  94. package/dist/config.d.ts +6 -0
  95. package/dist/config.d.ts.map +1 -0
  96. package/dist/config.js +111 -0
  97. package/dist/config.js.map +1 -0
  98. package/dist/devports-1.0.1.tgz +0 -0
  99. package/dist/execution.d.ts +31 -0
  100. package/dist/execution.d.ts.map +1 -0
  101. package/dist/execution.js +110 -0
  102. package/dist/execution.js.map +1 -0
  103. package/dist/gitignore.d.ts +22 -0
  104. package/dist/gitignore.d.ts.map +1 -0
  105. package/dist/gitignore.js +142 -0
  106. package/dist/gitignore.js.map +1 -0
  107. package/dist/index.d.ts +7 -0
  108. package/dist/index.d.ts.map +1 -0
  109. package/dist/index.js +6 -0
  110. package/dist/index.js.map +1 -0
  111. package/dist/port-manager.d.ts +33 -0
  112. package/dist/port-manager.d.ts.map +1 -0
  113. package/dist/port-manager.js +169 -0
  114. package/dist/port-manager.js.map +1 -0
  115. package/dist/port-utils.d.ts +9 -0
  116. package/dist/port-utils.d.ts.map +1 -0
  117. package/dist/port-utils.js +38 -0
  118. package/dist/port-utils.js.map +1 -0
  119. package/dist/render.d.ts +54 -0
  120. package/dist/render.d.ts.map +1 -0
  121. package/dist/render.js +286 -0
  122. package/dist/render.js.map +1 -0
  123. package/dist/services/lock-manager.d.ts +46 -0
  124. package/dist/services/lock-manager.d.ts.map +1 -0
  125. package/dist/services/lock-manager.js +118 -0
  126. package/dist/services/lock-manager.js.map +1 -0
  127. package/dist/services/response-formatter.d.ts +45 -0
  128. package/dist/services/response-formatter.d.ts.map +1 -0
  129. package/dist/services/response-formatter.js +102 -0
  130. package/dist/services/response-formatter.js.map +1 -0
  131. package/dist/services/validation-service.d.ts +109 -0
  132. package/dist/services/validation-service.d.ts.map +1 -0
  133. package/dist/services/validation-service.js +267 -0
  134. package/dist/services/validation-service.js.map +1 -0
  135. package/dist/setup.d.ts +20 -0
  136. package/dist/setup.d.ts.map +1 -0
  137. package/dist/setup.js +245 -0
  138. package/dist/setup.js.map +1 -0
  139. package/dist/types.d.ts +29 -0
  140. package/dist/types.d.ts.map +1 -0
  141. package/dist/types.js +18 -0
  142. package/dist/types.js.map +1 -0
  143. package/dist/validation.d.ts +69 -0
  144. package/dist/validation.d.ts.map +1 -0
  145. package/dist/validation.js +344 -0
  146. package/dist/validation.js.map +1 -0
  147. package/dist/worktree.d.ts +24 -0
  148. package/dist/worktree.d.ts.map +1 -0
  149. package/dist/worktree.js +245 -0
  150. package/dist/worktree.js.map +1 -0
  151. package/package.json +90 -6
@@ -0,0 +1,164 @@
1
+ #!/bin/zsh
2
+ #compdef devports
3
+
4
+ _devports() {
5
+ local curcontext="$curcontext" state line
6
+ typeset -A opt_args
7
+
8
+ local cmd=$words[2]
9
+ local subcmd=$words[3]
10
+
11
+ # Handle first argument (command)
12
+ if [[ $CURRENT -eq 2 ]]; then
13
+ compadd allocate release list status check reserve unreserve info render gitignore setup worktree completion
14
+ return 0
15
+ fi
16
+
17
+ # Handle arguments for specific commands
18
+ case $cmd in
19
+ allocate)
20
+ _arguments \
21
+ '1:project name:($(devports allocate --completion projects 2>/dev/null))' \
22
+ '2:service name:' \
23
+ '(-t --type)'{-t,--type}'[Service type]:type:($(devports allocate --completion types 2>/dev/null | tr '\''\n'\'' '\'' '\''))' \
24
+ '(-q --quiet)'{-q,--quiet}'[Only output the port number]' \
25
+ '--json[Output result as JSON]'
26
+ ;;
27
+ release)
28
+ # Skip completion if --port flag is used
29
+ if [[ ${words[*]} =~ "--port" ]] || [[ ${words[*]} =~ " -p " ]]; then
30
+ _arguments \
31
+ '(-a --all)'{-a,--all}'[Release all ports for the project]' \
32
+ '(-p --port)'{-p,--port}'[Release port by number]' \
33
+ '(-q --quiet)'{-q,--quiet}'[Only output the result]' \
34
+ '--json[Output result as JSON]'
35
+ return 0
36
+ fi
37
+
38
+ if [[ $CURRENT -eq 3 ]]; then
39
+ # First argument: project name
40
+ local projects=($(devports release --completion projects 2>/dev/null))
41
+ compadd -a projects
42
+ return 0
43
+ elif [[ $CURRENT -eq 4 ]]; then
44
+ # Second argument: service name for the specific project
45
+ local project=$words[3]
46
+ local services=($(devports release --completion services --project "$project" 2>/dev/null))
47
+ compadd -a services
48
+ return 0
49
+ fi
50
+ _arguments \
51
+ '(-a --all)'{-a,--all}'[Release all ports for the project]' \
52
+ '(-p --port)'{-p,--port}'[Release port by number]' \
53
+ '(-q --quiet)'{-q,--quiet}'[Only output the result]' \
54
+ '--json[Output result as JSON]'
55
+ ;;
56
+ list)
57
+ _arguments \
58
+ '(-p --project)'{-p,--project}'[Filter by project]:project:($(devports list --completion projects 2>/dev/null | tr '\''\n'\'' '\'' '\''))' \
59
+ '(-t --type)'{-t,--type}'[Filter by service type]:type:($(devports list --completion types 2>/dev/null | tr '\''\n'\'' '\'' '\''))' \
60
+ '(-q --quiet)'{-q,--quiet}'[Only output port numbers]' \
61
+ '--json[Output result as JSON]'
62
+ ;;
63
+ status)
64
+ _arguments \
65
+ '--json[Output result as JSON]'
66
+ ;;
67
+ check)
68
+ _arguments \
69
+ '1:port number: ' \
70
+ '(-q --quiet)'{-q,--quiet}'[Only output the result]' \
71
+ '--json[Output result as JSON]'
72
+ ;;
73
+ reserve)
74
+ _arguments \
75
+ '1:port number: ' \
76
+ '2:reason: ' \
77
+ '(-q --quiet)'{-q,--quiet}'[Only output the result]' \
78
+ '--json[Output result as JSON]'
79
+ ;;
80
+ unreserve)
81
+ _arguments \
82
+ '1:port number: ' \
83
+ '(-q --quiet)'{-q,--quiet}'[Only output the result]' \
84
+ '--json[Output result as JSON]'
85
+ ;;
86
+ info)
87
+ if [[ $CURRENT -eq 3 ]]; then
88
+ # Complete project names
89
+ local projects=($(devports list --completion projects 2>/dev/null))
90
+ compadd -a projects
91
+ elif [[ $CURRENT -eq 4 ]]; then
92
+ # Complete service names for the project
93
+ local project=$words[3]
94
+ local services=($(devports list --project "$project" --completion services 2>/dev/null))
95
+ compadd -a services
96
+ fi
97
+ _arguments \
98
+ '--json[Output result as JSON]'
99
+ ;;
100
+ render)
101
+ # Complete .devports files
102
+ _arguments \
103
+ '1:template file:_files -g "*.devports"' \
104
+ '(-p --project)'{-p,--project}'[Project name]: ' \
105
+ '(-o --output)'{-o,--output}'[Output file]:file:_files' \
106
+ '--json[Output result as JSON]'
107
+ ;;
108
+ gitignore)
109
+ _arguments \
110
+ '(-c --clean)'{-c,--clean}'[Remove devports entries from .gitignore]' \
111
+ '(-p --preview)'{-p,--preview}'[Preview changes without modifying files]' \
112
+ '--json[Output result as JSON]'
113
+ ;;
114
+ setup)
115
+ _arguments \
116
+ '(-t --template)'{-t,--template}'[Template file]:template:_files -g "*.devports"' \
117
+ '(-s --services)'{-s,--services}'[Services to set up (comma-separated)]: ' \
118
+ '(-f --force)'{-f,--force}'[Overwrite existing files]' \
119
+ '--skip-render[Skip auto-rendering *.devports files]' \
120
+ '(-h --post-hook)'{-h,--post-hook}'[Script to run after setup]:script:_files' \
121
+ '--json[Output result as JSON]'
122
+ ;;
123
+ worktree)
124
+ if [[ $CURRENT -eq 3 ]]; then
125
+ _values 'worktree command' \
126
+ 'add:Create a git worktree' \
127
+ 'remove:Remove a git worktree'
128
+ else
129
+ case $subcmd in
130
+ add)
131
+ _arguments \
132
+ '1:worktree path:_directories' \
133
+ '(-b --branch)'{-b,--branch}'[Branch name]: ' \
134
+ '(-s --services)'{-s,--services}'[Services to set up (comma-separated)]: ' \
135
+ '(-e --env-file)'{-e,--env-file}'[Custom .env file name]: ' \
136
+ '(-t --template)'{-t,--template}'[Template file]:template:_files -g "*.devports"' \
137
+ '(-h --post-hook)'{-h,--post-hook}'[Script to run after setup]:script:_files' \
138
+ '--no-env[Skip .env file creation]' \
139
+ '--json[Output result as JSON]'
140
+ ;;
141
+ remove)
142
+ _arguments \
143
+ '1:worktree path:_directories' \
144
+ '(-f --force)'{-f,--force}'[Force removal even if directory has changes]' \
145
+ '--json[Output result as JSON]'
146
+ ;;
147
+ esac
148
+ fi
149
+ ;;
150
+ completion)
151
+ if [[ $CURRENT -eq 3 ]]; then
152
+ compadd bash zsh
153
+ else
154
+ _arguments \
155
+ '(-i --install)'{-i,--install}'[Install completion to shell configuration]' \
156
+ '(-u --uninstall)'{-u,--uninstall}'[Remove completion from shell configuration]' \
157
+ '(-c --check)'{-c,--check}'[Check if completion is installed]' \
158
+ '--json[Output result as JSON]'
159
+ fi
160
+ ;;
161
+ esac
162
+ }
163
+
164
+ compdef _devports devports
@@ -0,0 +1,6 @@
1
+ import type { Config, Registry } from './types.js';
2
+ export declare function ensureConfigDir(): void;
3
+ export declare function loadConfig(): Config;
4
+ export declare function loadRegistry(): Registry;
5
+ export declare function saveRegistry(registry: Registry): void;
6
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAsCnD,wBAAgB,eAAe,IAAI,IAAI,CAWtC;AAED,wBAAgB,UAAU,IAAI,MAAM,CAgCnC;AAED,wBAAgB,YAAY,IAAI,QAAQ,CAwCvC;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CASrD"}
package/dist/config.js ADDED
@@ -0,0 +1,111 @@
1
+ import { homedir } from 'os';
2
+ import { join } from 'path';
3
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
4
+ function getConfigDir() {
5
+ return (process.env.DEVPORTS_CONFIG_DIR ?? join(homedir(), '.config', 'devports'));
6
+ }
7
+ function getConfigFile() {
8
+ return join(getConfigDir(), 'config.json');
9
+ }
10
+ function getRegistryFile() {
11
+ return join(getConfigDir(), 'ports.json');
12
+ }
13
+ const DEFAULT_CONFIG = {
14
+ ranges: {
15
+ postgres: { start: 5434, end: 5499 },
16
+ mysql: { start: 3308, end: 3399 },
17
+ redis: { start: 6381, end: 6399 },
18
+ api: { start: 3002, end: 3099 },
19
+ app: { start: 5002, end: 5999 },
20
+ custom: { start: 8002, end: 8999 },
21
+ },
22
+ };
23
+ const DEFAULT_REGISTRY = {
24
+ allocations: [],
25
+ reservations: [
26
+ {
27
+ port: 8080,
28
+ reason: 'Common development server port',
29
+ reservedAt: new Date().toISOString(),
30
+ },
31
+ ],
32
+ };
33
+ export function ensureConfigDir() {
34
+ const configDir = getConfigDir();
35
+ if (!existsSync(configDir)) {
36
+ try {
37
+ mkdirSync(configDir, { recursive: true });
38
+ }
39
+ catch (error) {
40
+ throw new Error(`Failed to create config directory at ${configDir}: ${error.message}`);
41
+ }
42
+ }
43
+ }
44
+ export function loadConfig() {
45
+ ensureConfigDir();
46
+ const configFile = getConfigFile();
47
+ if (!existsSync(configFile)) {
48
+ try {
49
+ const defaultConfig = {
50
+ ...DEFAULT_CONFIG,
51
+ registryPath: getRegistryFile(),
52
+ };
53
+ writeFileSync(configFile, JSON.stringify(defaultConfig, null, 2));
54
+ return defaultConfig;
55
+ }
56
+ catch (error) {
57
+ throw new Error(`Failed to create config file at ${configFile}: ${error.message}`);
58
+ }
59
+ }
60
+ try {
61
+ const content = readFileSync(configFile, 'utf-8');
62
+ return JSON.parse(content);
63
+ }
64
+ catch (error) {
65
+ if (error instanceof SyntaxError) {
66
+ throw new Error(`Config file ${configFile} contains invalid JSON: ${error.message}`);
67
+ }
68
+ throw new Error(`Failed to read config file ${configFile}: ${error.message}`);
69
+ }
70
+ }
71
+ export function loadRegistry() {
72
+ const config = loadConfig();
73
+ const registryPath = config.registryPath;
74
+ if (!existsSync(registryPath)) {
75
+ try {
76
+ writeFileSync(registryPath, JSON.stringify(DEFAULT_REGISTRY, null, 2));
77
+ return DEFAULT_REGISTRY;
78
+ }
79
+ catch (error) {
80
+ throw new Error(`Failed to create registry file at ${registryPath}: ${error.message}`);
81
+ }
82
+ }
83
+ try {
84
+ const content = readFileSync(registryPath, 'utf-8');
85
+ const registry = JSON.parse(content);
86
+ // Validate registry structure
87
+ if (!registry.allocations || !Array.isArray(registry.allocations)) {
88
+ throw new Error('Registry file is corrupted: missing or invalid allocations array');
89
+ }
90
+ if (!registry.reservations || !Array.isArray(registry.reservations)) {
91
+ throw new Error('Registry file is corrupted: missing or invalid reservations array');
92
+ }
93
+ return registry;
94
+ }
95
+ catch (error) {
96
+ if (error instanceof SyntaxError) {
97
+ throw new Error(`Registry file ${registryPath} contains invalid JSON: ${error.message}`);
98
+ }
99
+ throw error;
100
+ }
101
+ }
102
+ export function saveRegistry(registry) {
103
+ const config = loadConfig();
104
+ try {
105
+ writeFileSync(config.registryPath, JSON.stringify(registry, null, 2));
106
+ }
107
+ catch (error) {
108
+ throw new Error(`Failed to save registry to ${config.registryPath}: ${error.message}`);
109
+ }
110
+ }
111
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
Binary file
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Secure command execution utilities
3
+ * Provides safe alternatives to execSync for command injection prevention
4
+ */
5
+ import { SpawnOptions } from 'child_process';
6
+ /**
7
+ * Safe command execution using spawn with argument arrays
8
+ * Prevents shell injection by not using shell interpolation
9
+ */
10
+ export declare function safeExec(command: string, args: string[], options?: SpawnOptions): Promise<{
11
+ stdout: string;
12
+ stderr: string;
13
+ exitCode: number;
14
+ }>;
15
+ /**
16
+ * Safe git worktree add command
17
+ */
18
+ export declare function safeGitWorktreeAdd(path: string, branch: string, options?: SpawnOptions): Promise<void>;
19
+ /**
20
+ * Safe git worktree remove command
21
+ */
22
+ export declare function safeGitWorktreeRemove(path: string, force?: boolean, options?: SpawnOptions): Promise<void>;
23
+ /**
24
+ * Safe script execution with controlled environment
25
+ */
26
+ export declare function safeScriptExecution(scriptPath: string, env?: Record<string, string>, options?: SpawnOptions): Promise<void>;
27
+ /**
28
+ * Validate that a file is safe to execute as a script
29
+ */
30
+ export declare function validateExecutableScript(scriptPath: string): void;
31
+ //# sourceMappingURL=execution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../src/execution.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAS,YAAY,EAAE,MAAM,eAAe,CAAC;AAGpD;;;GAGG;AACH,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAkC/D;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CAef;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,MAAM,EACZ,KAAK,GAAE,OAAe,EACtB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EAChC,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAkBjE"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Secure command execution utilities
3
+ * Provides safe alternatives to execSync for command injection prevention
4
+ */
5
+ import { spawn } from 'child_process';
6
+ import { statSync } from 'fs';
7
+ /**
8
+ * Safe command execution using spawn with argument arrays
9
+ * Prevents shell injection by not using shell interpolation
10
+ */
11
+ export async function safeExec(command, args, options = {}) {
12
+ return new Promise((resolve, reject) => {
13
+ const child = spawn(command, args, {
14
+ ...options,
15
+ stdio: ['pipe', 'pipe', 'pipe'],
16
+ });
17
+ let stdout = '';
18
+ let stderr = '';
19
+ if (child.stdout) {
20
+ child.stdout.on('data', (data) => {
21
+ stdout += data.toString();
22
+ });
23
+ }
24
+ if (child.stderr) {
25
+ child.stderr.on('data', (data) => {
26
+ stderr += data.toString();
27
+ });
28
+ }
29
+ child.on('close', (code) => {
30
+ resolve({
31
+ stdout: stdout.trim(),
32
+ stderr: stderr.trim(),
33
+ exitCode: code ?? 0,
34
+ });
35
+ });
36
+ child.on('error', (error) => {
37
+ reject(error);
38
+ });
39
+ });
40
+ }
41
+ /**
42
+ * Safe git worktree add command
43
+ */
44
+ export async function safeGitWorktreeAdd(path, branch, options = {}) {
45
+ const result = await safeExec('git', ['worktree', 'add', path, '-b', branch], {
46
+ ...options,
47
+ stdio: 'inherit',
48
+ });
49
+ if (result.exitCode !== 0) {
50
+ throw new Error(`Git worktree add failed: ${result.stderr || 'Unknown error'}`);
51
+ }
52
+ }
53
+ /**
54
+ * Safe git worktree remove command
55
+ */
56
+ export async function safeGitWorktreeRemove(path, force = false, options = {}) {
57
+ const args = ['worktree', 'remove'];
58
+ if (force) {
59
+ args.push('--force');
60
+ }
61
+ args.push(path);
62
+ const result = await safeExec('git', args, {
63
+ ...options,
64
+ stdio: 'inherit',
65
+ });
66
+ if (result.exitCode !== 0) {
67
+ throw new Error(`Git worktree remove failed: ${result.stderr || 'Unknown error'}`);
68
+ }
69
+ }
70
+ /**
71
+ * Safe script execution with controlled environment
72
+ */
73
+ export async function safeScriptExecution(scriptPath, env = {}, options = {}) {
74
+ // First make the script executable
75
+ await safeExec('chmod', ['+x', scriptPath]);
76
+ // Then execute it with controlled environment
77
+ const result = await safeExec(scriptPath, [], {
78
+ ...options,
79
+ env: {
80
+ ...process.env,
81
+ ...env,
82
+ },
83
+ stdio: 'inherit',
84
+ });
85
+ if (result.exitCode !== 0) {
86
+ throw new Error(`Script execution failed: ${result.stderr || 'Unknown error'}`);
87
+ }
88
+ }
89
+ /**
90
+ * Validate that a file is safe to execute as a script
91
+ */
92
+ export function validateExecutableScript(scriptPath) {
93
+ try {
94
+ const stats = statSync(scriptPath);
95
+ if (!stats.isFile()) {
96
+ throw new Error('Script path is not a file');
97
+ }
98
+ // Check if executable on Unix-like systems
99
+ if (process.platform !== 'win32') {
100
+ const mode = stats.mode;
101
+ if (!(mode & parseInt('0100', 8))) {
102
+ throw new Error('Script is not executable');
103
+ }
104
+ }
105
+ }
106
+ catch (error) {
107
+ throw new Error(`Script validation failed: ${error.message}`);
108
+ }
109
+ }
110
+ //# sourceMappingURL=execution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execution.js","sourceRoot":"","sources":["../src/execution.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export interface GitignoreResult {
2
+ added: string[];
3
+ existing: string[];
4
+ devportsFiles: string[];
5
+ }
6
+ /**
7
+ * Find all *.devports files and add corresponding entries to .gitignore
8
+ */
9
+ export declare function updateGitignore(options?: {
10
+ dryRun?: boolean;
11
+ }): Promise<GitignoreResult>;
12
+ /**
13
+ * Remove devports-related entries from .gitignore
14
+ */
15
+ export declare function cleanGitignore(options?: {
16
+ dryRun?: boolean;
17
+ }): Promise<GitignoreResult>;
18
+ /**
19
+ * List what would be added to .gitignore without making changes
20
+ */
21
+ export declare function previewGitignore(): Promise<GitignoreResult>;
22
+ //# sourceMappingURL=gitignore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitignore.d.ts","sourceRoot":"","sources":["../src/gitignore.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC,OAAO,CAAC,eAAe,CAAC,CA6E1B;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC,OAAO,CAAC,eAAe,CAAC,CAkF1B;AAED;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,eAAe,CAAC,CAEjE"}
@@ -0,0 +1,142 @@
1
+ import { existsSync, readFileSync, writeFileSync } from 'fs';
2
+ import { glob } from 'glob';
3
+ /**
4
+ * Find all *.devports files and add corresponding entries to .gitignore
5
+ */
6
+ export async function updateGitignore(options = {}) {
7
+ // Find all *.devports files
8
+ const devportsFiles = await glob('**/*.devports', {
9
+ ignore: ['node_modules/**', '.git/**'],
10
+ });
11
+ if (devportsFiles.length === 0) {
12
+ return {
13
+ added: [],
14
+ existing: [],
15
+ devportsFiles: [],
16
+ };
17
+ }
18
+ // Generate target filenames (remove .devports extension)
19
+ const targetFiles = devportsFiles.map((file) => file.replace(/\.devports$/, ''));
20
+ // Read existing .gitignore
21
+ const gitignorePath = '.gitignore';
22
+ let gitignoreContent = '';
23
+ const existingEntries = new Set();
24
+ if (existsSync(gitignorePath)) {
25
+ gitignoreContent = readFileSync(gitignorePath, 'utf-8');
26
+ // Parse existing entries (ignore comments and empty lines)
27
+ const lines = gitignoreContent
28
+ .split('\n')
29
+ .map((line) => line.trim())
30
+ .filter((line) => line && !line.startsWith('#'));
31
+ for (const line of lines) {
32
+ existingEntries.add(line);
33
+ }
34
+ }
35
+ // Determine which entries to add
36
+ const toAdd = [];
37
+ const existing = [];
38
+ for (const targetFile of targetFiles) {
39
+ if (existingEntries.has(targetFile)) {
40
+ existing.push(targetFile);
41
+ }
42
+ else {
43
+ toAdd.push(targetFile);
44
+ }
45
+ }
46
+ // Add new entries if not in dry-run mode
47
+ if (!options.dryRun && toAdd.length > 0) {
48
+ let newContent = gitignoreContent;
49
+ // Add header comment if this is the first devports entry
50
+ const hasDevportsComment = gitignoreContent.includes('# devports generated files');
51
+ if (!hasDevportsComment && toAdd.length > 0) {
52
+ if (newContent && !newContent.endsWith('\n')) {
53
+ newContent += '\n';
54
+ }
55
+ newContent += '\n# devports generated files\n';
56
+ }
57
+ // Add new entries
58
+ for (const file of toAdd) {
59
+ newContent += `${file}\n`;
60
+ }
61
+ writeFileSync(gitignorePath, newContent);
62
+ }
63
+ return {
64
+ added: toAdd,
65
+ existing,
66
+ devportsFiles,
67
+ };
68
+ }
69
+ /**
70
+ * Remove devports-related entries from .gitignore
71
+ */
72
+ export async function cleanGitignore(options = {}) {
73
+ const gitignorePath = '.gitignore';
74
+ if (!existsSync(gitignorePath)) {
75
+ return {
76
+ added: [],
77
+ existing: [],
78
+ devportsFiles: [],
79
+ };
80
+ }
81
+ // Find all *.devports files to determine what should be in gitignore
82
+ const devportsFiles = await glob('**/*.devports', {
83
+ ignore: ['node_modules/**', '.git/**'],
84
+ });
85
+ const targetFiles = devportsFiles.map((file) => file.replace(/\.devports$/, ''));
86
+ // Read and parse .gitignore
87
+ const gitignoreContent = readFileSync(gitignorePath, 'utf-8');
88
+ const lines = gitignoreContent.split('\n');
89
+ const newLines = [];
90
+ const removed = [];
91
+ let inDevportsSection = false;
92
+ for (const line of lines) {
93
+ const trimmedLine = line.trim();
94
+ // Track if we're in the devports section
95
+ if (trimmedLine === '# devports generated files') {
96
+ inDevportsSection = true;
97
+ // Skip the header if no devports files exist
98
+ if (devportsFiles.length > 0) {
99
+ newLines.push(line);
100
+ }
101
+ continue;
102
+ }
103
+ // If we hit a new section comment or end of devports entries
104
+ if (inDevportsSection &&
105
+ trimmedLine.startsWith('#') &&
106
+ trimmedLine !== '# devports generated files') {
107
+ inDevportsSection = false;
108
+ }
109
+ // Remove entries that correspond to existing .devports files
110
+ if (inDevportsSection && trimmedLine && !trimmedLine.startsWith('#')) {
111
+ if (targetFiles.includes(trimmedLine)) {
112
+ removed.push(trimmedLine);
113
+ continue; // Skip this line
114
+ }
115
+ }
116
+ // Check if this is a stale entry (target file exists but no .devports file)
117
+ if (inDevportsSection && trimmedLine && !trimmedLine.startsWith('#')) {
118
+ const hasDevportsFile = devportsFiles.some((devFile) => devFile.replace(/\.devports$/, '') === trimmedLine);
119
+ if (!hasDevportsFile) {
120
+ removed.push(trimmedLine);
121
+ continue; // Skip stale entries
122
+ }
123
+ }
124
+ newLines.push(line);
125
+ }
126
+ // Write updated .gitignore if not in dry-run mode
127
+ if (!options.dryRun && removed.length > 0) {
128
+ writeFileSync(gitignorePath, newLines.join('\n'));
129
+ }
130
+ return {
131
+ added: [],
132
+ existing: targetFiles.filter((file) => !removed.includes(file)),
133
+ devportsFiles,
134
+ };
135
+ }
136
+ /**
137
+ * List what would be added to .gitignore without making changes
138
+ */
139
+ export async function previewGitignore() {
140
+ return updateGitignore({ dryRun: true });
141
+ }
142
+ //# sourceMappingURL=gitignore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitignore.js","sourceRoot":"","sources":["../src/gitignore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export { allocatePort, releasePort, releasePortByNumber, listAllocations, getStatus, reservePort, unreservePort, } from './port-manager.js';
2
+ export { loadConfig, loadRegistry, saveRegistry, ensureConfigDir, } from './config.js';
3
+ export { checkPortInUse, findAvailablePort } from './port-utils.js';
4
+ export { setupCurrentDirectory } from './setup.js';
5
+ export type { SetupOptions, SetupResult } from './setup.js';
6
+ export type { PortRange, Config, PortAllocation, Registry } from './types.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,YAAY,EACZ,WAAW,EACX,mBAAmB,EACnB,eAAe,EACf,SAAS,EACT,WAAW,EACX,aAAa,GACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEnD,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE5D,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ // Public API for programmatic usage
2
+ export { allocatePort, releasePort, releasePortByNumber, listAllocations, getStatus, reservePort, unreservePort, } from './port-manager.js';
3
+ export { loadConfig, loadRegistry, saveRegistry, ensureConfigDir, } from './config.js';
4
+ export { checkPortInUse, findAvailablePort } from './port-utils.js';
5
+ export { setupCurrentDirectory } from './setup.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,OAAO,EACL,YAAY,EACZ,WAAW,EACX,mBAAmB,EACnB,eAAe,EACf,SAAS,EACT,WAAW,EACX,aAAa,GACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC"}