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 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
@@ -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.44";
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
- if (!await packageJsonPath.exists()) {
4632
- const packageJson = {
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 './registry.js';
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 './registry.js';
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 registryTsTemplate = `import type { TaskFn } from 'hostctl';
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 '../task.js';
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);