pokit 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/pok.ts +182 -24
- package/package.json +5 -9
- package/src/init.ts +65 -0
package/bin/pok.ts
CHANGED
|
@@ -2,41 +2,199 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* pokit - Global CLI launcher for pok
|
|
4
4
|
*
|
|
5
|
-
* This is
|
|
6
|
-
* 1.
|
|
7
|
-
* 2.
|
|
8
|
-
* 3.
|
|
5
|
+
* This is the global CLI entry point that:
|
|
6
|
+
* 1. Searches for pok.config.ts (or .config/pok.config.ts) starting from cwd
|
|
7
|
+
* 2. Loads and validates the config
|
|
8
|
+
* 3. Resolves paths relative to config file location
|
|
9
|
+
* 4. Dynamically imports adapters
|
|
10
|
+
* 5. Calls runCli() with resolved configuration
|
|
9
11
|
*
|
|
10
12
|
* Install globally with: bun add -g pokit
|
|
11
|
-
* Then run `pok` from any project with
|
|
13
|
+
* Then run `pok` from any project with a pok.config.ts file.
|
|
12
14
|
*/
|
|
13
15
|
|
|
16
|
+
import { resolve } from 'bun';
|
|
17
|
+
import * as fs from 'fs';
|
|
18
|
+
import * as path from 'path';
|
|
19
|
+
|
|
20
|
+
// Handle init before config discovery - must work without a config file
|
|
21
|
+
const args = process.argv.slice(2);
|
|
22
|
+
if (args[0] === 'init') {
|
|
23
|
+
const { runInit } = await import('../src/init');
|
|
24
|
+
await runInit();
|
|
25
|
+
process.exit(0);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Simple inline config file search (no external dependencies).
|
|
30
|
+
* Searches for pok.config.ts starting from startDir, walking up the tree.
|
|
31
|
+
*/
|
|
32
|
+
function findConfigFileSimple(startDir: string): { configPath: string; configDir: string } | null {
|
|
33
|
+
let dir = startDir;
|
|
34
|
+
|
|
35
|
+
while (true) {
|
|
36
|
+
// Check for pok.config.ts in current directory
|
|
37
|
+
const configPath = path.join(dir, 'pok.config.ts');
|
|
38
|
+
if (fs.existsSync(configPath)) {
|
|
39
|
+
return { configPath, configDir: dir };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Check for .config/pok.config.ts
|
|
43
|
+
const dotConfigPath = path.join(dir, '.config', 'pok.config.ts');
|
|
44
|
+
if (fs.existsSync(dotConfigPath)) {
|
|
45
|
+
return { configPath: dotConfigPath, configDir: dir };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Move up to parent directory
|
|
49
|
+
const parentDir = path.dirname(dir);
|
|
50
|
+
if (parentDir === dir) {
|
|
51
|
+
// Reached filesystem root
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
dir = parentDir;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
14
58
|
async function main() {
|
|
59
|
+
const cwd = process.cwd();
|
|
60
|
+
|
|
61
|
+
// Step 1: Find config file using simple inline search
|
|
62
|
+
const configResult = findConfigFileSimple(cwd);
|
|
63
|
+
|
|
64
|
+
if (!configResult) {
|
|
65
|
+
console.error(`Error: No pok configuration found.
|
|
66
|
+
|
|
67
|
+
Run \`pok init\` to create a pok.config.ts file.
|
|
68
|
+
`);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const { configPath, configDir } = configResult;
|
|
73
|
+
|
|
74
|
+
// Step 2: Dynamically resolve @pokit/config from the project directory
|
|
75
|
+
let configModule: {
|
|
76
|
+
validateConfig: (config: unknown, configPath: string) => {
|
|
77
|
+
commandsDir: string;
|
|
78
|
+
projectRoot?: string;
|
|
79
|
+
appName?: string;
|
|
80
|
+
reporterAdapter: string;
|
|
81
|
+
prompter: string;
|
|
82
|
+
tabs?: string;
|
|
83
|
+
version?: string;
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
|
|
15
87
|
try {
|
|
16
|
-
const
|
|
17
|
-
await
|
|
18
|
-
} catch
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
88
|
+
const configModulePath = await resolve('@pokit/config', configDir);
|
|
89
|
+
configModule = await import(configModulePath);
|
|
90
|
+
} catch {
|
|
91
|
+
console.error(
|
|
92
|
+
`Error: @pokit/config is not installed in ${configDir}\n\n` +
|
|
93
|
+
'Install it with:\n' +
|
|
94
|
+
' bun add @pokit/config\n'
|
|
95
|
+
);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Step 3: Load and validate config using the dynamically imported module
|
|
100
|
+
let config: ReturnType<typeof configModule.validateConfig>;
|
|
101
|
+
try {
|
|
102
|
+
const rawConfig = await import(configPath);
|
|
103
|
+
config = configModule.validateConfig(rawConfig.default, configPath);
|
|
104
|
+
} catch (err) {
|
|
105
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
106
|
+
console.error(`Error: Failed to load config from ${configPath}\n`);
|
|
107
|
+
console.error(errorMessage);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Step 4: Resolve paths relative to config file location
|
|
112
|
+
const commandsDir = path.resolve(configDir, config.commandsDir);
|
|
113
|
+
const projectRoot = config.projectRoot
|
|
114
|
+
? path.resolve(configDir, config.projectRoot)
|
|
115
|
+
: configDir;
|
|
116
|
+
|
|
117
|
+
// Verify commands directory exists
|
|
118
|
+
if (!fs.existsSync(commandsDir)) {
|
|
119
|
+
console.error(`Error: Commands directory not found: ${commandsDir}\n`);
|
|
120
|
+
console.error(`The commandsDir path in ${configPath} resolves to a directory that doesn't exist.`);
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Step 5: Resolve @pokit/core from the config directory
|
|
125
|
+
let corePath: string;
|
|
126
|
+
try {
|
|
127
|
+
corePath = await resolve('@pokit/core', configDir);
|
|
128
|
+
} catch {
|
|
129
|
+
console.error(
|
|
130
|
+
`Error: @pokit/core is not installed in ${configDir}\n\n` +
|
|
131
|
+
'Install it with:\n' +
|
|
132
|
+
' bun add @pokit/core\n'
|
|
133
|
+
);
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Step 6: Dynamically import adapters from the config directory
|
|
138
|
+
let createReporterAdapter: (options?: { output?: unknown }) => unknown;
|
|
139
|
+
let createPrompter: () => unknown;
|
|
140
|
+
let createTabs: (() => unknown) | undefined;
|
|
141
|
+
|
|
142
|
+
// Import reporter adapter
|
|
143
|
+
try {
|
|
144
|
+
const reporterPath = await resolve(config.reporterAdapter, configDir);
|
|
145
|
+
const reporterModule = await import(reporterPath);
|
|
146
|
+
createReporterAdapter = reporterModule.createReporterAdapter;
|
|
147
|
+
} catch {
|
|
148
|
+
console.error(
|
|
149
|
+
`Error: Reporter adapter "${config.reporterAdapter}" is not installed.\n\n` +
|
|
150
|
+
`Install it with:\n` +
|
|
151
|
+
` bun add ${config.reporterAdapter}\n`
|
|
152
|
+
);
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Import prompter
|
|
157
|
+
try {
|
|
158
|
+
const prompterPath = await resolve(config.prompter, configDir);
|
|
159
|
+
const prompterModule = await import(prompterPath);
|
|
160
|
+
createPrompter = prompterModule.createPrompter;
|
|
161
|
+
} catch {
|
|
162
|
+
console.error(
|
|
163
|
+
`Error: Prompter "${config.prompter}" is not installed.\n\n` +
|
|
164
|
+
`Install it with:\n` +
|
|
165
|
+
` bun add ${config.prompter}\n`
|
|
166
|
+
);
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Import tabs adapter if configured
|
|
171
|
+
if (config.tabs) {
|
|
172
|
+
try {
|
|
173
|
+
const tabsPath = await resolve(config.tabs, configDir);
|
|
174
|
+
const tabsModule = await import(tabsPath);
|
|
175
|
+
createTabs = tabsModule.createTabs;
|
|
176
|
+
} catch {
|
|
26
177
|
console.error(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
' - @pokit/core installed in your project\n\n' +
|
|
31
|
-
'Install with:\n' +
|
|
32
|
-
' bun add @pokit/core\n'
|
|
178
|
+
`Error: Tabs adapter "${config.tabs}" is not installed.\n\n` +
|
|
179
|
+
`Install it with:\n` +
|
|
180
|
+
` bun add ${config.tabs}\n`
|
|
33
181
|
);
|
|
34
182
|
process.exit(1);
|
|
35
183
|
}
|
|
36
|
-
|
|
37
|
-
// Re-throw other errors
|
|
38
|
-
throw error;
|
|
39
184
|
}
|
|
185
|
+
|
|
186
|
+
// Step 7: Import core and call runCli
|
|
187
|
+
const { runCli } = await import(corePath);
|
|
188
|
+
|
|
189
|
+
await runCli(process.argv.slice(2), {
|
|
190
|
+
commandsDir,
|
|
191
|
+
projectRoot,
|
|
192
|
+
appName: config.appName,
|
|
193
|
+
version: config.version,
|
|
194
|
+
reporterAdapter: createReporterAdapter(),
|
|
195
|
+
prompter: createPrompter(),
|
|
196
|
+
tabs: createTabs?.(),
|
|
197
|
+
});
|
|
40
198
|
}
|
|
41
199
|
|
|
42
200
|
main().catch((err) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pokit",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Global CLI launcher for pok - install once, run anywhere",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"pok": "./bin/pok.ts"
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
|
-
"bin"
|
|
20
|
+
"bin",
|
|
21
|
+
"src"
|
|
21
22
|
],
|
|
22
23
|
"publishConfig": {
|
|
23
24
|
"access": "public"
|
|
@@ -32,10 +33,5 @@
|
|
|
32
33
|
"cli",
|
|
33
34
|
"pok",
|
|
34
35
|
"pokit"
|
|
35
|
-
]
|
|
36
|
-
|
|
37
|
-
"@pokit/core": "^0.0.2",
|
|
38
|
-
"@pokit/reporter-clack": "^0.0.2",
|
|
39
|
-
"@pokit/prompter-clack": "^0.0.2"
|
|
40
|
-
}
|
|
41
|
-
}
|
|
36
|
+
]
|
|
37
|
+
}
|
package/src/init.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pok init command
|
|
3
|
+
*
|
|
4
|
+
* Scaffolds a basic pok.config.ts file for new projects.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { resolve } from 'bun';
|
|
8
|
+
import * as fs from 'fs';
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
|
|
11
|
+
const CONFIG_FILENAME = 'pok.config.ts';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Fallback template used when @pokit/config isn't installed yet.
|
|
15
|
+
* This enables bootstrapping new projects.
|
|
16
|
+
*/
|
|
17
|
+
const FALLBACK_CONFIG_TEMPLATE = `import { defineConfig } from 'pokit'
|
|
18
|
+
|
|
19
|
+
export default defineConfig({
|
|
20
|
+
commandsDir: './commands',
|
|
21
|
+
reporterAdapter: '@pokit/reporter-clack',
|
|
22
|
+
prompter: '@pokit/prompter-clack',
|
|
23
|
+
})
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Try to get CONFIG_TEMPLATE from @pokit/config, falling back to hardcoded template.
|
|
28
|
+
*/
|
|
29
|
+
async function getConfigTemplate(cwd: string): Promise<string> {
|
|
30
|
+
try {
|
|
31
|
+
const configModulePath = await resolve('@pokit/config', cwd);
|
|
32
|
+
const configModule = await import(configModulePath);
|
|
33
|
+
return configModule.CONFIG_TEMPLATE ?? FALLBACK_CONFIG_TEMPLATE;
|
|
34
|
+
} catch {
|
|
35
|
+
// @pokit/config not installed yet - use fallback for bootstrapping
|
|
36
|
+
return FALLBACK_CONFIG_TEMPLATE;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Run the init command to create a pok.config.ts file
|
|
42
|
+
*/
|
|
43
|
+
export async function runInit(): Promise<void> {
|
|
44
|
+
const cwd = process.cwd();
|
|
45
|
+
const configPath = path.join(cwd, CONFIG_FILENAME);
|
|
46
|
+
|
|
47
|
+
// Check if config already exists
|
|
48
|
+
if (fs.existsSync(configPath)) {
|
|
49
|
+
console.error('Error: pok.config.ts already exists in this directory.');
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Get the config template (from @pokit/config or fallback)
|
|
54
|
+
const template = await getConfigTemplate(cwd);
|
|
55
|
+
|
|
56
|
+
// Write the config file
|
|
57
|
+
fs.writeFileSync(configPath, template);
|
|
58
|
+
|
|
59
|
+
console.log(`Created pok.config.ts
|
|
60
|
+
|
|
61
|
+
Next steps:
|
|
62
|
+
1. Create a commands/ directory
|
|
63
|
+
2. Add your first command file
|
|
64
|
+
3. Run \`pok\` to see available commands`);
|
|
65
|
+
}
|