hostctl 0.1.45 → 0.1.47
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/README.md +2 -0
- package/dist/bin/hostctl.js +20 -154
- package/dist/bin/hostctl.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +44 -174
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -7154,7 +7154,7 @@ declare class HostctlApi {
|
|
|
7154
7154
|
}
|
|
7155
7155
|
|
|
7156
7156
|
type TaskRegistry = {
|
|
7157
|
-
register: (name: string, task: TaskFn) => TaskRegistry;
|
|
7157
|
+
register: <TParams extends TaskParams = TaskParams, TReturn extends RunFnReturnValue = RunFnReturnValue>(name: string, task: TaskFn<TParams, TReturn>) => TaskRegistry;
|
|
7158
7158
|
get: (name: string) => TaskFn | undefined;
|
|
7159
7159
|
tasks: () => Array<[string, TaskFn]>;
|
|
7160
7160
|
has: (name: string) => boolean;
|
package/dist/index.js
CHANGED
|
@@ -2718,7 +2718,7 @@ var Verbosity = {
|
|
|
2718
2718
|
};
|
|
2719
2719
|
|
|
2720
2720
|
// src/version.ts
|
|
2721
|
-
var version = "0.1.
|
|
2721
|
+
var version = "0.1.47";
|
|
2722
2722
|
|
|
2723
2723
|
// src/commands/pkg/create.ts
|
|
2724
2724
|
import { promises as fs5 } from "fs";
|
|
@@ -2755,8 +2755,7 @@ var packageJsonTsTemplate = (packageName) => `{
|
|
|
2755
2755
|
"author": "",
|
|
2756
2756
|
"license": "MIT",
|
|
2757
2757
|
"dependencies": {
|
|
2758
|
-
"hostctl": "^0.1.42"
|
|
2759
|
-
"zod": "^4.1.13"
|
|
2758
|
+
"hostctl": "^0.1.42"
|
|
2760
2759
|
},
|
|
2761
2760
|
"devDependencies": {
|
|
2762
2761
|
"typescript": "^5.8.3",
|
|
@@ -2789,8 +2788,7 @@ var packageJsonJsTemplate = (packageName) => `{
|
|
|
2789
2788
|
"author": "",
|
|
2790
2789
|
"license": "MIT",
|
|
2791
2790
|
"dependencies": {
|
|
2792
|
-
"hostctl": "^0.1.42"
|
|
2793
|
-
"zod": "^4.1.13"
|
|
2791
|
+
"hostctl": "^0.1.42"
|
|
2794
2792
|
},
|
|
2795
2793
|
"engines": {
|
|
2796
2794
|
"node": ">=24"
|
|
@@ -2825,157 +2823,21 @@ function registryPrefixFromPackageName(packageName) {
|
|
|
2825
2823
|
const normalized = withoutPrefix.replace(/[^a-zA-Z0-9]+/g, ".").replace(/^\.|\.$/g, "");
|
|
2826
2824
|
return normalized || "example";
|
|
2827
2825
|
}
|
|
2828
|
-
var indexTsTemplate = (registryPrefix) => `import { createRegistry } from '
|
|
2826
|
+
var indexTsTemplate = (registryPrefix) => `import { createRegistry } from 'hostctl';
|
|
2829
2827
|
import hello from './tasks/hello.js';
|
|
2830
2828
|
|
|
2831
2829
|
export { hello };
|
|
2832
2830
|
|
|
2833
2831
|
export const registry = createRegistry().register('${registryPrefix}.hello', hello);
|
|
2834
2832
|
`;
|
|
2835
|
-
var indexJsTemplate = (registryPrefix) => `import { createRegistry } from '
|
|
2833
|
+
var indexJsTemplate = (registryPrefix) => `import { createRegistry } from 'hostctl';
|
|
2836
2834
|
import hello from './tasks/hello.js';
|
|
2837
2835
|
|
|
2838
2836
|
export { hello };
|
|
2839
2837
|
|
|
2840
2838
|
export const registry = createRegistry().register('${registryPrefix}.hello', hello);
|
|
2841
2839
|
`;
|
|
2842
|
-
var
|
|
2843
|
-
|
|
2844
|
-
export type TaskRegistry = {
|
|
2845
|
-
register: (name: string, task: TaskFn) => TaskRegistry;
|
|
2846
|
-
get: (name: string) => TaskFn | undefined;
|
|
2847
|
-
tasks: () => Array<[string, TaskFn]>;
|
|
2848
|
-
has: (name: string) => boolean;
|
|
2849
|
-
names: () => string[];
|
|
2850
|
-
size: () => number;
|
|
2851
|
-
};
|
|
2852
|
-
|
|
2853
|
-
function isTaskFnLike(candidate: unknown): candidate is TaskFn {
|
|
2854
|
-
return (
|
|
2855
|
-
typeof candidate === 'function' &&
|
|
2856
|
-
!!candidate &&
|
|
2857
|
-
'task' in (candidate as Record<string, unknown>) &&
|
|
2858
|
-
typeof (candidate as { task?: unknown }).task === 'object'
|
|
2859
|
-
);
|
|
2860
|
-
}
|
|
2861
|
-
|
|
2862
|
-
export function createRegistry(): TaskRegistry {
|
|
2863
|
-
const entries = new Map<string, TaskFn>();
|
|
2864
|
-
|
|
2865
|
-
const registry: TaskRegistry = {
|
|
2866
|
-
register(name: string, task: TaskFn) {
|
|
2867
|
-
if (!name || typeof name !== 'string') {
|
|
2868
|
-
throw new Error('Registry task name must be a non-empty string.');
|
|
2869
|
-
}
|
|
2870
|
-
if (!isTaskFnLike(task)) {
|
|
2871
|
-
throw new Error(\`Registry task '\${name}' must be a TaskFn.\`);
|
|
2872
|
-
}
|
|
2873
|
-
if (entries.has(name)) {
|
|
2874
|
-
throw new Error(\`Registry already has a task named '\${name}'.\`);
|
|
2875
|
-
}
|
|
2876
|
-
if (task.task) {
|
|
2877
|
-
task.task.name = name;
|
|
2878
|
-
}
|
|
2879
|
-
entries.set(name, task);
|
|
2880
|
-
return registry;
|
|
2881
|
-
},
|
|
2882
|
-
get(name: string) {
|
|
2883
|
-
return entries.get(name);
|
|
2884
|
-
},
|
|
2885
|
-
tasks() {
|
|
2886
|
-
return Array.from(entries.entries()).sort(([a], [b]) => a.localeCompare(b));
|
|
2887
|
-
},
|
|
2888
|
-
has(name: string) {
|
|
2889
|
-
return entries.has(name);
|
|
2890
|
-
},
|
|
2891
|
-
names() {
|
|
2892
|
-
return Array.from(entries.keys()).sort((a, b) => a.localeCompare(b));
|
|
2893
|
-
},
|
|
2894
|
-
size() {
|
|
2895
|
-
return entries.size;
|
|
2896
|
-
},
|
|
2897
|
-
};
|
|
2898
|
-
|
|
2899
|
-
return registry;
|
|
2900
|
-
}
|
|
2901
|
-
`;
|
|
2902
|
-
var registryJsTemplate = `export function createRegistry() {
|
|
2903
|
-
const entries = new Map();
|
|
2904
|
-
|
|
2905
|
-
const registry = {
|
|
2906
|
-
register(name, task) {
|
|
2907
|
-
if (!name || typeof name !== 'string') {
|
|
2908
|
-
throw new Error('Registry task name must be a non-empty string.');
|
|
2909
|
-
}
|
|
2910
|
-
if (!task || typeof task !== 'function' || !task.task) {
|
|
2911
|
-
throw new Error(\`Registry task '\${name}' must be a TaskFn.\`);
|
|
2912
|
-
}
|
|
2913
|
-
if (entries.has(name)) {
|
|
2914
|
-
throw new Error(\`Registry already has a task named '\${name}'.\`);
|
|
2915
|
-
}
|
|
2916
|
-
if (task.task) {
|
|
2917
|
-
task.task.name = name;
|
|
2918
|
-
}
|
|
2919
|
-
entries.set(name, task);
|
|
2920
|
-
return registry;
|
|
2921
|
-
},
|
|
2922
|
-
get(name) {
|
|
2923
|
-
return entries.get(name);
|
|
2924
|
-
},
|
|
2925
|
-
tasks() {
|
|
2926
|
-
return Array.from(entries.entries()).sort(([a], [b]) => a.localeCompare(b));
|
|
2927
|
-
},
|
|
2928
|
-
has(name) {
|
|
2929
|
-
return entries.has(name);
|
|
2930
|
-
},
|
|
2931
|
-
names() {
|
|
2932
|
-
return Array.from(entries.keys()).sort((a, b) => a.localeCompare(b));
|
|
2933
|
-
},
|
|
2934
|
-
size() {
|
|
2935
|
-
return entries.size;
|
|
2936
|
-
},
|
|
2937
|
-
};
|
|
2938
|
-
|
|
2939
|
-
return registry;
|
|
2940
|
-
}
|
|
2941
|
-
`;
|
|
2942
|
-
var taskWrapperTsTemplate = `import { task as baseTask, type RunFn, type RunFnReturnValue, type TaskFn, type TaskOptions, type TaskParams } from 'hostctl';
|
|
2943
|
-
import type { ZodTypeAny } from 'zod';
|
|
2944
|
-
|
|
2945
|
-
export type TaskOptionsWithSchema = TaskOptions & {
|
|
2946
|
-
inputSchema?: ZodTypeAny;
|
|
2947
|
-
outputSchema?: ZodTypeAny;
|
|
2948
|
-
};
|
|
2949
|
-
|
|
2950
|
-
export function task<TParams extends TaskParams, TReturn extends RunFnReturnValue>(
|
|
2951
|
-
runFn: RunFn<TParams, TReturn>,
|
|
2952
|
-
options?: TaskOptionsWithSchema,
|
|
2953
|
-
): TaskFn<TParams, TReturn> {
|
|
2954
|
-
const taskFn = baseTask(runFn, options as TaskOptions);
|
|
2955
|
-
if (options?.inputSchema) {
|
|
2956
|
-
(taskFn.task as any).inputSchema = options.inputSchema;
|
|
2957
|
-
}
|
|
2958
|
-
if (options?.outputSchema) {
|
|
2959
|
-
(taskFn.task as any).outputSchema = options.outputSchema;
|
|
2960
|
-
}
|
|
2961
|
-
return taskFn;
|
|
2962
|
-
}
|
|
2963
|
-
`;
|
|
2964
|
-
var taskWrapperJsTemplate = `import { task as baseTask } from 'hostctl';
|
|
2965
|
-
|
|
2966
|
-
export function task(runFn, options) {
|
|
2967
|
-
const taskFn = baseTask(runFn, options);
|
|
2968
|
-
if (options?.inputSchema) {
|
|
2969
|
-
taskFn.task.inputSchema = options.inputSchema;
|
|
2970
|
-
}
|
|
2971
|
-
if (options?.outputSchema) {
|
|
2972
|
-
taskFn.task.outputSchema = options.outputSchema;
|
|
2973
|
-
}
|
|
2974
|
-
return taskFn;
|
|
2975
|
-
}
|
|
2976
|
-
`;
|
|
2977
|
-
var sampleTaskTsTemplate = `import { task, type TaskContext } from '../task.js';
|
|
2978
|
-
import { z } from 'zod';
|
|
2840
|
+
var sampleTaskTsTemplate = `import { task, type TaskContext, z } from 'hostctl';
|
|
2979
2841
|
|
|
2980
2842
|
const HelloInputSchema = z.object({
|
|
2981
2843
|
name: z.string().optional(),
|
|
@@ -3008,8 +2870,7 @@ export default task(run, {
|
|
|
3008
2870
|
outputSchema: HelloOutputSchema,
|
|
3009
2871
|
});
|
|
3010
2872
|
`;
|
|
3011
|
-
var sampleTaskJsTemplate = `import { task } from '
|
|
3012
|
-
import { z } from 'zod';
|
|
2873
|
+
var sampleTaskJsTemplate = `import { task, z } from 'hostctl';
|
|
3013
2874
|
|
|
3014
2875
|
const HelloInputSchema = z.object({
|
|
3015
2876
|
name: z.string().optional(),
|
|
@@ -3055,7 +2916,7 @@ hostctl run . ${registryPrefix}.hello name:Hostctl excited:true
|
|
|
3055
2916
|
- Tasks live under \`src/\` and export a default \`task(...)\`.
|
|
3056
2917
|
- \`src/index.(ts|js)\` re-exports tasks and publishes a registry for discovery.
|
|
3057
2918
|
- Task names are unqualified; the registry assigns qualified names.
|
|
3058
|
-
- Schema helpers come from \`zod\` and are attached to tasks for discovery.
|
|
2919
|
+
- Schema helpers come from \`hostctl\` (re-exported \`zod\`) and are attached to tasks for discovery.
|
|
3059
2920
|
|
|
3060
2921
|
## Publish
|
|
3061
2922
|
|
|
@@ -3093,8 +2954,6 @@ async function createPackage(packageName, options) {
|
|
|
3093
2954
|
await fs5.writeFile(path3.join(packageDir, "tsconfig.json"), tsconfigTemplate);
|
|
3094
2955
|
await fs5.mkdir(path3.join(packageDir, "src", "tasks"), { recursive: true });
|
|
3095
2956
|
await fs5.writeFile(path3.join(packageDir, "src", "index.ts"), indexTsTemplate(registryPrefix));
|
|
3096
|
-
await fs5.writeFile(path3.join(packageDir, "src", "registry.ts"), registryTsTemplate);
|
|
3097
|
-
await fs5.writeFile(path3.join(packageDir, "src", "task.ts"), taskWrapperTsTemplate);
|
|
3098
2957
|
await fs5.writeFile(path3.join(packageDir, "src", "tasks", "hello.ts"), sampleTaskTsTemplate);
|
|
3099
2958
|
await fs5.writeFile(path3.join(packageDir, "README.md"), readmeTemplate(packageJsonName, registryPrefix, true));
|
|
3100
2959
|
await fs5.writeFile(path3.join(packageDir, ".gitignore"), gitignoreTemplate);
|
|
@@ -3102,8 +2961,6 @@ async function createPackage(packageName, options) {
|
|
|
3102
2961
|
await fs5.writeFile(path3.join(packageDir, "package.json"), packageJsonJsTemplate(packageJsonName));
|
|
3103
2962
|
await fs5.mkdir(path3.join(packageDir, "src", "tasks"), { recursive: true });
|
|
3104
2963
|
await fs5.writeFile(path3.join(packageDir, "src", "index.js"), indexJsTemplate(registryPrefix));
|
|
3105
|
-
await fs5.writeFile(path3.join(packageDir, "src", "registry.js"), registryJsTemplate);
|
|
3106
|
-
await fs5.writeFile(path3.join(packageDir, "src", "task.js"), taskWrapperJsTemplate);
|
|
3107
2964
|
await fs5.writeFile(path3.join(packageDir, "src", "tasks", "hello.js"), sampleTaskJsTemplate);
|
|
3108
2965
|
await fs5.writeFile(path3.join(packageDir, "README.md"), readmeTemplate(packageJsonName, registryPrefix, false));
|
|
3109
2966
|
await fs5.writeFile(path3.join(packageDir, ".gitignore"), gitignoreTemplate);
|
|
@@ -3944,15 +3801,24 @@ var PackageManager = class {
|
|
|
3944
3801
|
}
|
|
3945
3802
|
async ensurePackagesDirHasPackageJson(packagesDir) {
|
|
3946
3803
|
const packageJsonPath = packagesDir.join("package.json");
|
|
3947
|
-
|
|
3948
|
-
|
|
3804
|
+
const hostctlOverride = process.env.HOSTCTL_PKG_HOSTCTL_OVERRIDE;
|
|
3805
|
+
const overrideValue = hostctlOverride ? hostctlOverride.startsWith("file:") ? hostctlOverride : `file:${Path.new(hostctlOverride).absolute().toString()}` : void 0;
|
|
3806
|
+
let packageJson;
|
|
3807
|
+
if (await packageJsonPath.exists()) {
|
|
3808
|
+
const raw = await fs6.readFile(packageJsonPath.toString(), "utf-8");
|
|
3809
|
+
packageJson = JSON.parse(raw);
|
|
3810
|
+
} else {
|
|
3811
|
+
packageJson = {
|
|
3949
3812
|
name: "hostctl-packages",
|
|
3950
3813
|
version: "1.0.0",
|
|
3951
3814
|
description: "Hostctl package management directory",
|
|
3952
3815
|
private: true
|
|
3953
3816
|
};
|
|
3954
|
-
await fs6.writeFile(packageJsonPath.toString(), JSON.stringify(packageJson, null, 2));
|
|
3955
3817
|
}
|
|
3818
|
+
if (overrideValue) {
|
|
3819
|
+
packageJson.overrides = { ...packageJson.overrides ?? {}, hostctl: overrideValue };
|
|
3820
|
+
}
|
|
3821
|
+
await fs6.writeFile(packageJsonPath.toString(), JSON.stringify(packageJson, null, 2));
|
|
3956
3822
|
}
|
|
3957
3823
|
// Scan node_modules for the real installed package (by name or repo match)
|
|
3958
3824
|
async findRealInstalledNpmPackagePath(packagesDir, source) {
|
|
@@ -7437,23 +7303,24 @@ function isTaskFnLike2(candidate) {
|
|
|
7437
7303
|
}
|
|
7438
7304
|
function createRegistry() {
|
|
7439
7305
|
const entries = /* @__PURE__ */ new Map();
|
|
7306
|
+
function register(name, task6) {
|
|
7307
|
+
if (!name || typeof name !== "string") {
|
|
7308
|
+
throw new Error("Registry task name must be a non-empty string.");
|
|
7309
|
+
}
|
|
7310
|
+
if (!isTaskFnLike2(task6)) {
|
|
7311
|
+
throw new Error(`Registry task '${name}' must be a TaskFn.`);
|
|
7312
|
+
}
|
|
7313
|
+
if (entries.has(name)) {
|
|
7314
|
+
throw new Error(`Registry already has a task named '${name}'.`);
|
|
7315
|
+
}
|
|
7316
|
+
if (task6.task) {
|
|
7317
|
+
task6.task.name = name;
|
|
7318
|
+
}
|
|
7319
|
+
entries.set(name, task6);
|
|
7320
|
+
return registry2;
|
|
7321
|
+
}
|
|
7440
7322
|
const registry2 = {
|
|
7441
|
-
register
|
|
7442
|
-
if (!name || typeof name !== "string") {
|
|
7443
|
-
throw new Error("Registry task name must be a non-empty string.");
|
|
7444
|
-
}
|
|
7445
|
-
if (!isTaskFnLike2(task6)) {
|
|
7446
|
-
throw new Error(`Registry task '${name}' must be a TaskFn.`);
|
|
7447
|
-
}
|
|
7448
|
-
if (entries.has(name)) {
|
|
7449
|
-
throw new Error(`Registry already has a task named '${name}'.`);
|
|
7450
|
-
}
|
|
7451
|
-
if (task6.task) {
|
|
7452
|
-
task6.task.name = name;
|
|
7453
|
-
}
|
|
7454
|
-
entries.set(name, task6);
|
|
7455
|
-
return registry2;
|
|
7456
|
-
},
|
|
7323
|
+
register,
|
|
7457
7324
|
get(name) {
|
|
7458
7325
|
return entries.get(name);
|
|
7459
7326
|
},
|
|
@@ -33599,22 +33466,25 @@ function resolvedTaskName(task6) {
|
|
|
33599
33466
|
}
|
|
33600
33467
|
return deriveCoreTaskName(task6) ?? taskName ?? null;
|
|
33601
33468
|
}
|
|
33602
|
-
function collectTasksFrom(source, tasks, seen) {
|
|
33469
|
+
function collectTasksFrom(source, tasks, seen, pathParts = []) {
|
|
33603
33470
|
if (!source) return;
|
|
33604
33471
|
if (isTaskFnLike3(source)) {
|
|
33605
33472
|
if (!seen.has(source)) {
|
|
33473
|
+
if (!hasExplicitName(source) && pathParts.length > 0) {
|
|
33474
|
+
source.task.name = `core.${pathParts.join(".")}`;
|
|
33475
|
+
}
|
|
33606
33476
|
tasks.push(source);
|
|
33607
33477
|
seen.add(source);
|
|
33608
33478
|
}
|
|
33609
33479
|
return;
|
|
33610
33480
|
}
|
|
33611
33481
|
if (Array.isArray(source)) {
|
|
33612
|
-
source.forEach((entry) => collectTasksFrom(entry, tasks, seen));
|
|
33482
|
+
source.forEach((entry) => collectTasksFrom(entry, tasks, seen, pathParts));
|
|
33613
33483
|
return;
|
|
33614
33484
|
}
|
|
33615
33485
|
if (isTraversableObject(source)) {
|
|
33616
|
-
for (const value of Object.
|
|
33617
|
-
collectTasksFrom(value, tasks, seen);
|
|
33486
|
+
for (const [key, value] of Object.entries(source)) {
|
|
33487
|
+
collectTasksFrom(value, tasks, seen, [...pathParts, key]);
|
|
33618
33488
|
}
|
|
33619
33489
|
}
|
|
33620
33490
|
}
|