hostctl 0.1.44 → 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/README.md
CHANGED
|
@@ -93,12 +93,14 @@ npx hostctl run core.echo message:hello
|
|
|
93
93
|
```
|
|
94
94
|
Local directories are executed directly and are not installable via `hostctl pkg install`.
|
|
95
95
|
- **Remote orchestration**
|
|
96
|
+
|
|
96
97
|
```bash
|
|
97
98
|
hostctl run -r -t ubuntu core.net.interfaces --json
|
|
98
99
|
```
|
|
99
100
|
|
|
100
101
|
- `-r/--remote` targets hosts selected by tags via SSH.
|
|
101
102
|
- `-t/--tag` is greedy; use `--` before positional args when needed.
|
|
103
|
+
|
|
102
104
|
- **From npm or git**
|
|
103
105
|
```bash
|
|
104
106
|
hostctl run hostctl-hello greet name:Phil
|
package/dist/bin/hostctl.js
CHANGED
|
@@ -4211,7 +4211,7 @@ var ParamMap = class _ParamMap {
|
|
|
4211
4211
|
import * as z from "zod";
|
|
4212
4212
|
|
|
4213
4213
|
// src/version.ts
|
|
4214
|
-
var version = "0.1.
|
|
4214
|
+
var version = "0.1.47";
|
|
4215
4215
|
|
|
4216
4216
|
// src/app.ts
|
|
4217
4217
|
import { retryUntilDefined } from "ts-retry";
|
|
@@ -4628,15 +4628,24 @@ var PackageManager = class {
|
|
|
4628
4628
|
}
|
|
4629
4629
|
async ensurePackagesDirHasPackageJson(packagesDir) {
|
|
4630
4630
|
const packageJsonPath = packagesDir.join("package.json");
|
|
4631
|
-
|
|
4632
|
-
|
|
4631
|
+
const hostctlOverride = process.env.HOSTCTL_PKG_HOSTCTL_OVERRIDE;
|
|
4632
|
+
const overrideValue = hostctlOverride ? hostctlOverride.startsWith("file:") ? hostctlOverride : `file:${Path.new(hostctlOverride).absolute().toString()}` : void 0;
|
|
4633
|
+
let packageJson;
|
|
4634
|
+
if (await packageJsonPath.exists()) {
|
|
4635
|
+
const raw = await fs6.readFile(packageJsonPath.toString(), "utf-8");
|
|
4636
|
+
packageJson = JSON.parse(raw);
|
|
4637
|
+
} else {
|
|
4638
|
+
packageJson = {
|
|
4633
4639
|
name: "hostctl-packages",
|
|
4634
4640
|
version: "1.0.0",
|
|
4635
4641
|
description: "Hostctl package management directory",
|
|
4636
4642
|
private: true
|
|
4637
4643
|
};
|
|
4638
|
-
await fs6.writeFile(packageJsonPath.toString(), JSON.stringify(packageJson, null, 2));
|
|
4639
4644
|
}
|
|
4645
|
+
if (overrideValue) {
|
|
4646
|
+
packageJson.overrides = { ...packageJson.overrides ?? {}, hostctl: overrideValue };
|
|
4647
|
+
}
|
|
4648
|
+
await fs6.writeFile(packageJsonPath.toString(), JSON.stringify(packageJson, null, 2));
|
|
4640
4649
|
}
|
|
4641
4650
|
// Scan node_modules for the real installed package (by name or repo match)
|
|
4642
4651
|
async findRealInstalledNpmPackagePath(packagesDir, source) {
|
|
@@ -6122,8 +6131,7 @@ var packageJsonTsTemplate = (packageName) => `{
|
|
|
6122
6131
|
"author": "",
|
|
6123
6132
|
"license": "MIT",
|
|
6124
6133
|
"dependencies": {
|
|
6125
|
-
"hostctl": "^0.1.42"
|
|
6126
|
-
"zod": "^4.1.13"
|
|
6134
|
+
"hostctl": "^0.1.42"
|
|
6127
6135
|
},
|
|
6128
6136
|
"devDependencies": {
|
|
6129
6137
|
"typescript": "^5.8.3",
|
|
@@ -6156,8 +6164,7 @@ var packageJsonJsTemplate = (packageName) => `{
|
|
|
6156
6164
|
"author": "",
|
|
6157
6165
|
"license": "MIT",
|
|
6158
6166
|
"dependencies": {
|
|
6159
|
-
"hostctl": "^0.1.42"
|
|
6160
|
-
"zod": "^4.1.13"
|
|
6167
|
+
"hostctl": "^0.1.42"
|
|
6161
6168
|
},
|
|
6162
6169
|
"engines": {
|
|
6163
6170
|
"node": ">=24"
|
|
@@ -6192,157 +6199,21 @@ function registryPrefixFromPackageName(packageName) {
|
|
|
6192
6199
|
const normalized = withoutPrefix.replace(/[^a-zA-Z0-9]+/g, ".").replace(/^\.|\.$/g, "");
|
|
6193
6200
|
return normalized || "example";
|
|
6194
6201
|
}
|
|
6195
|
-
var indexTsTemplate = (registryPrefix) => `import { createRegistry } from '
|
|
6202
|
+
var indexTsTemplate = (registryPrefix) => `import { createRegistry } from 'hostctl';
|
|
6196
6203
|
import hello from './tasks/hello.js';
|
|
6197
6204
|
|
|
6198
6205
|
export { hello };
|
|
6199
6206
|
|
|
6200
6207
|
export const registry = createRegistry().register('${registryPrefix}.hello', hello);
|
|
6201
6208
|
`;
|
|
6202
|
-
var indexJsTemplate = (registryPrefix) => `import { createRegistry } from '
|
|
6209
|
+
var indexJsTemplate = (registryPrefix) => `import { createRegistry } from 'hostctl';
|
|
6203
6210
|
import hello from './tasks/hello.js';
|
|
6204
6211
|
|
|
6205
6212
|
export { hello };
|
|
6206
6213
|
|
|
6207
6214
|
export const registry = createRegistry().register('${registryPrefix}.hello', hello);
|
|
6208
6215
|
`;
|
|
6209
|
-
var
|
|
6210
|
-
|
|
6211
|
-
export type TaskRegistry = {
|
|
6212
|
-
register: (name: string, task: TaskFn) => TaskRegistry;
|
|
6213
|
-
get: (name: string) => TaskFn | undefined;
|
|
6214
|
-
tasks: () => Array<[string, TaskFn]>;
|
|
6215
|
-
has: (name: string) => boolean;
|
|
6216
|
-
names: () => string[];
|
|
6217
|
-
size: () => number;
|
|
6218
|
-
};
|
|
6219
|
-
|
|
6220
|
-
function isTaskFnLike(candidate: unknown): candidate is TaskFn {
|
|
6221
|
-
return (
|
|
6222
|
-
typeof candidate === 'function' &&
|
|
6223
|
-
!!candidate &&
|
|
6224
|
-
'task' in (candidate as Record<string, unknown>) &&
|
|
6225
|
-
typeof (candidate as { task?: unknown }).task === 'object'
|
|
6226
|
-
);
|
|
6227
|
-
}
|
|
6228
|
-
|
|
6229
|
-
export function createRegistry(): TaskRegistry {
|
|
6230
|
-
const entries = new Map<string, TaskFn>();
|
|
6231
|
-
|
|
6232
|
-
const registry: TaskRegistry = {
|
|
6233
|
-
register(name: string, task: TaskFn) {
|
|
6234
|
-
if (!name || typeof name !== 'string') {
|
|
6235
|
-
throw new Error('Registry task name must be a non-empty string.');
|
|
6236
|
-
}
|
|
6237
|
-
if (!isTaskFnLike(task)) {
|
|
6238
|
-
throw new Error(\`Registry task '\${name}' must be a TaskFn.\`);
|
|
6239
|
-
}
|
|
6240
|
-
if (entries.has(name)) {
|
|
6241
|
-
throw new Error(\`Registry already has a task named '\${name}'.\`);
|
|
6242
|
-
}
|
|
6243
|
-
if (task.task) {
|
|
6244
|
-
task.task.name = name;
|
|
6245
|
-
}
|
|
6246
|
-
entries.set(name, task);
|
|
6247
|
-
return registry;
|
|
6248
|
-
},
|
|
6249
|
-
get(name: string) {
|
|
6250
|
-
return entries.get(name);
|
|
6251
|
-
},
|
|
6252
|
-
tasks() {
|
|
6253
|
-
return Array.from(entries.entries()).sort(([a], [b]) => a.localeCompare(b));
|
|
6254
|
-
},
|
|
6255
|
-
has(name: string) {
|
|
6256
|
-
return entries.has(name);
|
|
6257
|
-
},
|
|
6258
|
-
names() {
|
|
6259
|
-
return Array.from(entries.keys()).sort((a, b) => a.localeCompare(b));
|
|
6260
|
-
},
|
|
6261
|
-
size() {
|
|
6262
|
-
return entries.size;
|
|
6263
|
-
},
|
|
6264
|
-
};
|
|
6265
|
-
|
|
6266
|
-
return registry;
|
|
6267
|
-
}
|
|
6268
|
-
`;
|
|
6269
|
-
var registryJsTemplate = `export function createRegistry() {
|
|
6270
|
-
const entries = new Map();
|
|
6271
|
-
|
|
6272
|
-
const registry = {
|
|
6273
|
-
register(name, task) {
|
|
6274
|
-
if (!name || typeof name !== 'string') {
|
|
6275
|
-
throw new Error('Registry task name must be a non-empty string.');
|
|
6276
|
-
}
|
|
6277
|
-
if (!task || typeof task !== 'function' || !task.task) {
|
|
6278
|
-
throw new Error(\`Registry task '\${name}' must be a TaskFn.\`);
|
|
6279
|
-
}
|
|
6280
|
-
if (entries.has(name)) {
|
|
6281
|
-
throw new Error(\`Registry already has a task named '\${name}'.\`);
|
|
6282
|
-
}
|
|
6283
|
-
if (task.task) {
|
|
6284
|
-
task.task.name = name;
|
|
6285
|
-
}
|
|
6286
|
-
entries.set(name, task);
|
|
6287
|
-
return registry;
|
|
6288
|
-
},
|
|
6289
|
-
get(name) {
|
|
6290
|
-
return entries.get(name);
|
|
6291
|
-
},
|
|
6292
|
-
tasks() {
|
|
6293
|
-
return Array.from(entries.entries()).sort(([a], [b]) => a.localeCompare(b));
|
|
6294
|
-
},
|
|
6295
|
-
has(name) {
|
|
6296
|
-
return entries.has(name);
|
|
6297
|
-
},
|
|
6298
|
-
names() {
|
|
6299
|
-
return Array.from(entries.keys()).sort((a, b) => a.localeCompare(b));
|
|
6300
|
-
},
|
|
6301
|
-
size() {
|
|
6302
|
-
return entries.size;
|
|
6303
|
-
},
|
|
6304
|
-
};
|
|
6305
|
-
|
|
6306
|
-
return registry;
|
|
6307
|
-
}
|
|
6308
|
-
`;
|
|
6309
|
-
var taskWrapperTsTemplate = `import { task as baseTask, type RunFn, type RunFnReturnValue, type TaskFn, type TaskOptions, type TaskParams } from 'hostctl';
|
|
6310
|
-
import type { ZodTypeAny } from 'zod';
|
|
6311
|
-
|
|
6312
|
-
export type TaskOptionsWithSchema = TaskOptions & {
|
|
6313
|
-
inputSchema?: ZodTypeAny;
|
|
6314
|
-
outputSchema?: ZodTypeAny;
|
|
6315
|
-
};
|
|
6316
|
-
|
|
6317
|
-
export function task<TParams extends TaskParams, TReturn extends RunFnReturnValue>(
|
|
6318
|
-
runFn: RunFn<TParams, TReturn>,
|
|
6319
|
-
options?: TaskOptionsWithSchema,
|
|
6320
|
-
): TaskFn<TParams, TReturn> {
|
|
6321
|
-
const taskFn = baseTask(runFn, options as TaskOptions);
|
|
6322
|
-
if (options?.inputSchema) {
|
|
6323
|
-
(taskFn.task as any).inputSchema = options.inputSchema;
|
|
6324
|
-
}
|
|
6325
|
-
if (options?.outputSchema) {
|
|
6326
|
-
(taskFn.task as any).outputSchema = options.outputSchema;
|
|
6327
|
-
}
|
|
6328
|
-
return taskFn;
|
|
6329
|
-
}
|
|
6330
|
-
`;
|
|
6331
|
-
var taskWrapperJsTemplate = `import { task as baseTask } from 'hostctl';
|
|
6332
|
-
|
|
6333
|
-
export function task(runFn, options) {
|
|
6334
|
-
const taskFn = baseTask(runFn, options);
|
|
6335
|
-
if (options?.inputSchema) {
|
|
6336
|
-
taskFn.task.inputSchema = options.inputSchema;
|
|
6337
|
-
}
|
|
6338
|
-
if (options?.outputSchema) {
|
|
6339
|
-
taskFn.task.outputSchema = options.outputSchema;
|
|
6340
|
-
}
|
|
6341
|
-
return taskFn;
|
|
6342
|
-
}
|
|
6343
|
-
`;
|
|
6344
|
-
var sampleTaskTsTemplate = `import { task, type TaskContext } from '../task.js';
|
|
6345
|
-
import { z } from 'zod';
|
|
6216
|
+
var sampleTaskTsTemplate = `import { task, type TaskContext, z } from 'hostctl';
|
|
6346
6217
|
|
|
6347
6218
|
const HelloInputSchema = z.object({
|
|
6348
6219
|
name: z.string().optional(),
|
|
@@ -6375,8 +6246,7 @@ export default task(run, {
|
|
|
6375
6246
|
outputSchema: HelloOutputSchema,
|
|
6376
6247
|
});
|
|
6377
6248
|
`;
|
|
6378
|
-
var sampleTaskJsTemplate = `import { task } from '
|
|
6379
|
-
import { z } from 'zod';
|
|
6249
|
+
var sampleTaskJsTemplate = `import { task, z } from 'hostctl';
|
|
6380
6250
|
|
|
6381
6251
|
const HelloInputSchema = z.object({
|
|
6382
6252
|
name: z.string().optional(),
|
|
@@ -6422,7 +6292,7 @@ hostctl run . ${registryPrefix}.hello name:Hostctl excited:true
|
|
|
6422
6292
|
- Tasks live under \`src/\` and export a default \`task(...)\`.
|
|
6423
6293
|
- \`src/index.(ts|js)\` re-exports tasks and publishes a registry for discovery.
|
|
6424
6294
|
- Task names are unqualified; the registry assigns qualified names.
|
|
6425
|
-
- Schema helpers come from \`zod\` and are attached to tasks for discovery.
|
|
6295
|
+
- Schema helpers come from \`hostctl\` (re-exported \`zod\`) and are attached to tasks for discovery.
|
|
6426
6296
|
|
|
6427
6297
|
## Publish
|
|
6428
6298
|
|
|
@@ -6460,8 +6330,6 @@ async function createPackage(packageName, options) {
|
|
|
6460
6330
|
await fs9.writeFile(path5.join(packageDir, "tsconfig.json"), tsconfigTemplate);
|
|
6461
6331
|
await fs9.mkdir(path5.join(packageDir, "src", "tasks"), { recursive: true });
|
|
6462
6332
|
await fs9.writeFile(path5.join(packageDir, "src", "index.ts"), indexTsTemplate(registryPrefix));
|
|
6463
|
-
await fs9.writeFile(path5.join(packageDir, "src", "registry.ts"), registryTsTemplate);
|
|
6464
|
-
await fs9.writeFile(path5.join(packageDir, "src", "task.ts"), taskWrapperTsTemplate);
|
|
6465
6333
|
await fs9.writeFile(path5.join(packageDir, "src", "tasks", "hello.ts"), sampleTaskTsTemplate);
|
|
6466
6334
|
await fs9.writeFile(path5.join(packageDir, "README.md"), readmeTemplate(packageJsonName, registryPrefix, true));
|
|
6467
6335
|
await fs9.writeFile(path5.join(packageDir, ".gitignore"), gitignoreTemplate);
|
|
@@ -6469,8 +6337,6 @@ async function createPackage(packageName, options) {
|
|
|
6469
6337
|
await fs9.writeFile(path5.join(packageDir, "package.json"), packageJsonJsTemplate(packageJsonName));
|
|
6470
6338
|
await fs9.mkdir(path5.join(packageDir, "src", "tasks"), { recursive: true });
|
|
6471
6339
|
await fs9.writeFile(path5.join(packageDir, "src", "index.js"), indexJsTemplate(registryPrefix));
|
|
6472
|
-
await fs9.writeFile(path5.join(packageDir, "src", "registry.js"), registryJsTemplate);
|
|
6473
|
-
await fs9.writeFile(path5.join(packageDir, "src", "task.js"), taskWrapperJsTemplate);
|
|
6474
6340
|
await fs9.writeFile(path5.join(packageDir, "src", "tasks", "hello.js"), sampleTaskJsTemplate);
|
|
6475
6341
|
await fs9.writeFile(path5.join(packageDir, "README.md"), readmeTemplate(packageJsonName, registryPrefix, false));
|
|
6476
6342
|
await fs9.writeFile(path5.join(packageDir, ".gitignore"), gitignoreTemplate);
|