pokit 0.0.14 → 0.0.16

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 (2) hide show
  1. package/bin/pok.ts +186 -15
  2. package/package.json +5 -2
package/bin/pok.ts CHANGED
@@ -55,6 +55,166 @@ function findConfigFileSimple(startDir: string): { configPath: string; configDir
55
55
  }
56
56
  }
57
57
 
58
+ /**
59
+ * Simple inline package.json search.
60
+ */
61
+ function findPackageJsonSimple(startDir: string): { pkgPath: string; pkgDir: string } | null {
62
+ let dir = startDir;
63
+
64
+ while (true) {
65
+ const pkgPath = path.join(dir, 'package.json');
66
+ if (fs.existsSync(pkgPath)) {
67
+ return { pkgPath, pkgDir: dir };
68
+ }
69
+
70
+ const parentDir = path.dirname(dir);
71
+ if (parentDir === dir) {
72
+ return null;
73
+ }
74
+ dir = parentDir;
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Try to resolve a module from the project directory, then from the launcher's own dependencies.
80
+ */
81
+ async function resolveModule(name: string, configDir: string) {
82
+ try {
83
+ // 1. Try resolving from the project's node_modules
84
+ const projectModulePath = await resolve(name, configDir);
85
+ return await import(projectModulePath);
86
+ } catch {
87
+ try {
88
+ // 2. Try resolving from the launcher's own dependencies
89
+ return await import(name);
90
+ } catch {
91
+ return null;
92
+ }
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Detect the package manager used in the project (simple version for launcher).
98
+ */
99
+ function getPackageManagerSimple(projectRoot: string): 'npm' | 'pnpm' | 'yarn' | 'bun' {
100
+ if (fs.existsSync(path.join(projectRoot, 'pnpm-lock.yaml'))) return 'pnpm';
101
+ if (
102
+ fs.existsSync(path.join(projectRoot, 'bun.lockb')) ||
103
+ fs.existsSync(path.join(projectRoot, 'bun.lock'))
104
+ )
105
+ return 'bun';
106
+ if (fs.existsSync(path.join(projectRoot, 'yarn.lock'))) return 'yarn';
107
+ return 'npm';
108
+ }
109
+
110
+ /**
111
+ * Simple dependency-free Yes/No prompt.
112
+ */
113
+ async function askYesNo(question: string): Promise<boolean> {
114
+ if (!process.stdout.isTTY) return false;
115
+
116
+ process.stdout.write(`${question} (Y/n) `);
117
+ for await (const line of console) {
118
+ const input = line.trim().toLowerCase();
119
+ if (input === '' || input === 'y' || input === 'yes') return true;
120
+ if (input === 'n' || input === 'no') return false;
121
+ process.stdout.write('Please enter y or n: ');
122
+ }
123
+ return false;
124
+ }
125
+
126
+ /**
127
+ * Ensure required pok modules are installed in the project.
128
+ */
129
+ async function ensureModulesInstalled(pkgDir: string, moduleNames: string[]): Promise<boolean> {
130
+ const pm = getPackageManagerSimple(pkgDir);
131
+ const installCmd =
132
+ pm === 'npm'
133
+ ? `npm install --save-dev ${moduleNames.join(' ')}`
134
+ : pm === 'pnpm'
135
+ ? `pnpm add -D ${moduleNames.join(' ')}`
136
+ : pm === 'yarn'
137
+ ? `yarn add -D ${moduleNames.join(' ')}`
138
+ : `bun add -d ${moduleNames.join(' ')}`;
139
+
140
+ const confirmed = await askYesNo(
141
+ `Required pok modules (${moduleNames.join(', ')}) are missing locally. Install them with ${pm}?`
142
+ );
143
+
144
+ if (!confirmed) return false;
145
+
146
+ console.log(`\nInstalling modules: ${installCmd}...\n`);
147
+
148
+ try {
149
+ const { $ } = await import('bun');
150
+ await $`${{ raw: installCmd }}`.cwd(pkgDir);
151
+ console.log('\nModules installed successfully!\n');
152
+ return true;
153
+ } catch (err) {
154
+ console.error(
155
+ `\nFailed to install modules: ${err instanceof Error ? err.message : String(err)}`
156
+ );
157
+ return false;
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Run pok in fallback mode when no config is found but package.json exists.
163
+ */
164
+ async function runInFallbackMode(pkgDir: string) {
165
+ let core = await resolveModule('@pokit/core', pkgDir);
166
+ let reporter = await resolveModule('@pokit/reporter-clack', pkgDir);
167
+ let prompter = await resolveModule('@pokit/prompter-clack', pkgDir);
168
+
169
+ if (!core || !reporter || !prompter) {
170
+ const missing = [];
171
+ if (!core) missing.push('@pokit/core');
172
+ if (!reporter) missing.push('@pokit/reporter-clack');
173
+ if (!prompter) missing.push('@pokit/prompter-clack');
174
+
175
+ if (await ensureModulesInstalled(pkgDir, missing)) {
176
+ // Retry resolution after installation
177
+ core = await resolveModule('@pokit/core', pkgDir);
178
+ reporter = await resolveModule('@pokit/reporter-clack', pkgDir);
179
+ prompter = await resolveModule('@pokit/prompter-clack', pkgDir);
180
+ }
181
+ }
182
+
183
+ if (!core || !reporter || !prompter) {
184
+ console.error(
185
+ `Error: Required pok modules not found.\n\n` +
186
+ `Install them in your project to enable the fallback menu:\n` +
187
+ ` bun add -d @pokit/core @pokit/reporter-clack @pokit/prompter-clack\n\n` +
188
+ `Or run \`pok init\` to bootstrap a configuration.`
189
+ );
190
+ process.exit(1);
191
+ }
192
+
193
+ const { runCli, defineCommand } = core;
194
+ const { createReporterAdapter } = reporter;
195
+ const { createPrompter } = prompter;
196
+ const { runInit } = await import('../src/init');
197
+
198
+ await runCli(process.argv.slice(2), {
199
+ commandsDir: path.join(pkgDir, 'commands'),
200
+ projectRoot: pkgDir,
201
+ appName: path.basename(pkgDir),
202
+ reporterAdapter: createReporterAdapter(),
203
+ prompter: createPrompter(),
204
+ pmScripts: true,
205
+ pmCommands: true,
206
+ extraCommands: {
207
+ init: defineCommand({
208
+ label: 'init',
209
+ description: 'Initialize pok config in this repo',
210
+ run: async () => {
211
+ await runInit();
212
+ },
213
+ }),
214
+ },
215
+ });
216
+ }
217
+
58
218
  async function main() {
59
219
  const processCwd = process.cwd();
60
220
 
@@ -62,7 +222,14 @@ async function main() {
62
222
  const configResult = findConfigFileSimple(processCwd);
63
223
 
64
224
  if (!configResult) {
65
- console.error(`Error: No pok configuration found.
225
+ // Look for package.json
226
+ const pkgJsonResult = findPackageJsonSimple(processCwd);
227
+ if (pkgJsonResult) {
228
+ await runInFallbackMode(pkgJsonResult.pkgDir);
229
+ return;
230
+ }
231
+
232
+ console.error(`Error: No pok configuration or package.json found.
66
233
 
67
234
  Run \`pok init\` to create a pok.config.ts file.
68
235
  `);
@@ -72,12 +239,15 @@ Run \`pok init\` to create a pok.config.ts file.
72
239
  const { configPath, configDir } = configResult;
73
240
 
74
241
  // Step 2: Dynamically resolve @pokit/core from the project directory
75
- let configModule: ConfigModule;
242
+ let configModule = await resolveModule('@pokit/core', configDir);
76
243
 
77
- try {
78
- const configModulePath = await resolve('@pokit/core', configDir);
79
- configModule = await import(configModulePath);
80
- } catch {
244
+ if (!configModule) {
245
+ if (await ensureModulesInstalled(configDir, ['@pokit/core'])) {
246
+ configModule = await resolveModule('@pokit/core', configDir);
247
+ }
248
+ }
249
+
250
+ if (!configModule) {
81
251
  console.error(
82
252
  `Error: @pokit/core is not installed in ${configDir}\n\n` +
83
253
  'Install it with:\n' +
@@ -107,7 +277,9 @@ Run \`pok init\` to create a pok.config.ts file.
107
277
  // Verify commands directory exists
108
278
  if (!fs.existsSync(commandsDir)) {
109
279
  console.error(`Error: Commands directory not found: ${commandsDir}\n`);
110
- console.error(`The commandsDir path in ${configPath} resolves to a directory that doesn't exist.`);
280
+ console.error(
281
+ `The commandsDir path in ${configPath} resolves to a directory that doesn't exist.`
282
+ );
111
283
  process.exit(1);
112
284
  }
113
285
 
@@ -120,14 +292,13 @@ Run \`pok init\` to create a pok.config.ts file.
120
292
  projectRoot: cwd, // core uses projectRoot, config uses cwd
121
293
  appName: config.appName,
122
294
  version: config.version,
123
- reporterAdapter: config.reporter,
124
- prompter: config.prompter,
125
- tabs: config.tabs,
126
- pmScripts: config.pmScripts,
127
- pmCommands: config.pmCommands,
128
- });
129
- }
130
-
295
+ reporterAdapter: config.reporter,
296
+ prompter: config.prompter,
297
+ tabs: config.tabs,
298
+ pmScripts: config.pmScripts,
299
+ pmCommands: config.pmCommands,
300
+ });
301
+ }
131
302
 
132
303
  main().catch((err) => {
133
304
  console.error(err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pokit",
3
- "version": "0.0.14",
3
+ "version": "0.0.16",
4
4
  "description": "Global CLI launcher for pok - install once, run anywhere",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -30,7 +30,10 @@
30
30
  "access": "public"
31
31
  },
32
32
  "devDependencies": {
33
- "@types/bun": "latest"
33
+ "@types/bun": "latest",
34
+ "@pokit/core": "0.0.15",
35
+ "@pokit/reporter-clack": "0.0.15",
36
+ "@pokit/prompter-clack": "0.0.15"
34
37
  },
35
38
  "engines": {
36
39
  "bun": ">=1.0.0"