@nodeint/migent 0.1.2 → 0.1.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/README.md CHANGED
@@ -17,9 +17,9 @@ where the process is.
17
17
  - [Supported CLIs](#supported-clis)
18
18
  - [Quickstart](#quickstart)
19
19
  - [Install](#install)
20
- - [Upgrade](#upgrade)
21
20
  - [Create a project](#create-a-project)
22
21
  - [Run](#run)
22
+ - [Next](#next)
23
23
  - [Concepts](#concepts)
24
24
  - [Current scope](#current-scope)
25
25
  - [Documentation](#documentation)
@@ -69,59 +69,56 @@ ones your configuration names.
69
69
 
70
70
  ## Quickstart
71
71
 
72
- Node.js 22+ on macOS or Linux, and authenticated provider CLIs named by your
73
- configuration.
72
+ Requires Node.js 22+ (macOS, Linux, or Windows) and the provider CLIs your
73
+ config uses, already signed in.
74
74
 
75
75
  ### Install
76
76
 
77
77
  ```bash
78
78
  npm install -g @nodeint/migent
79
+ migent --version
79
80
  ```
80
81
 
81
- Verify with `migent --version`.
82
-
83
- ### Upgrade
84
-
85
- ```bash
86
- npm install -g @nodeint/migent@latest
87
- ```
82
+ Upgrade with `npm install -g @nodeint/migent@latest`.
88
83
 
89
84
  ### Create a project
90
85
 
91
- From the project where agents will work:
86
+ From the repository where agents will work:
92
87
 
93
88
  ```bash
94
- migent init --preset plan
89
+ migent init
95
90
  ```
96
91
 
97
- `init` writes the config, a plan-and-review workflow, and a gitignore for local
98
- session state:
92
+ In a terminal, `init` walks you through the provider, model, and options, then
93
+ offers to install the Migent skill so agents in the project know how to run it.
94
+ Without a terminal, pass `--provider` and `--model` together. Pass `--skill` to
95
+ install the skill without the prompt.
96
+
97
+ It creates:
99
98
 
100
99
  ```text
101
100
  .migent/
102
- ├── config.yaml
103
- ├── .gitignore
101
+ ├── config.yaml # models and roles
102
+ ├── .gitignore # keeps sessions/ untracked
104
103
  └── workflows/
105
- └── plan.yaml
106
- ```
104
+ └── plan.yaml # plan-and-review workflow
107
105
 
108
- In a terminal, pick the provider, model, and prompted options from the lists.
109
- Pass `--provider` and `--model` together when input is not a terminal. Commit
110
- `config.yaml` and `workflows/`. Leave `.migent/sessions/` untracked.
106
+ .agents/skills/migent/ # only if you install the skill
107
+ ```
111
108
 
112
- Model and role shape is in [Providers and model configuration](https://github.com/nodeint/migent/blob/main/docs/providers.md).
113
- A full plan workflow is in [Writing workflows](https://github.com/nodeint/migent/blob/main/docs/workflows.md#complete-example).
109
+ Commit `config.yaml` and `workflows/`. To add the skill later, run
110
+ `migent skill install`.
114
111
 
115
112
  ### Run
116
113
 
117
- From that project or any of its subdirectories:
114
+ From the project or any subdirectory:
118
115
 
119
116
  ```bash
120
117
  migent start plan --task "Plan the account settings redesign"
121
118
  ```
122
119
 
123
- Migent runs the next eligible stage until the workflow completes or stops.
124
- Progress goes to stderr. Stdout is one JSON result.
120
+ Migent runs each eligible stage until the workflow completes or stops. Progress
121
+ goes to stderr; stdout is a single JSON result. Then inspect or resume:
125
122
 
126
123
  ```bash
127
124
  migent sessions
@@ -129,9 +126,12 @@ migent watch <session-id>
129
126
  migent continue <session-id>
130
127
  ```
131
128
 
132
- Command fields and exit codes are in
133
- [CLI commands and execution controls](https://github.com/nodeint/migent/blob/main/docs/cli.md). Session files are in
134
- [Sessions and workflow composition](https://github.com/nodeint/migent/blob/main/docs/sessions.md).
129
+ ### Next
130
+
131
+ - [Providers and model configuration](https://github.com/nodeint/migent/blob/main/docs/providers.md)
132
+ - [Writing workflows](https://github.com/nodeint/migent/blob/main/docs/workflows.md#complete-example)
133
+ - [CLI commands and exit codes](https://github.com/nodeint/migent/blob/main/docs/cli.md)
134
+ - [Sessions and workflow composition](https://github.com/nodeint/migent/blob/main/docs/sessions.md)
135
135
 
136
136
  ## Concepts
137
137
 
@@ -185,22 +185,8 @@ pnpm test
185
185
  pnpm migent --help # run the local build
186
186
  ```
187
187
 
188
- ### Releasing
189
-
190
- All four packages share one version. Bump it, commit, and push a matching tag:
191
-
192
- ```bash
193
- pnpm -r exec npm pkg set version=0.2.0
194
- pnpm install
195
- git commit -am "Release 0.2.0"
196
- git tag v0.2.0
197
- git push origin main v0.2.0
198
- ```
199
-
200
- The tag runs `.github/workflows/release.yml`, which builds, tests, packs, and
201
- stages each package through npm trusted publishing. Nothing goes live until a
202
- maintainer approves the staged versions on npmjs.com (Staged Packages tab) or
203
- with `npm stage approve`, kernel first and `@nodeint/migent` last.
188
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for testing rules, platform notes, and
189
+ the release process.
204
190
 
205
191
  ## License
206
192
 
@@ -18,6 +18,7 @@ export declare function runInit(workspace: string, options?: {
18
18
  model?: string | null;
19
19
  options?: readonly string[];
20
20
  preset?: string;
21
+ skill?: boolean;
21
22
  interactive?: boolean;
22
23
  adapters?: Record<string, AgentAdapter> | null;
23
24
  which?: Which | null;
@@ -5,12 +5,14 @@ import { diagnose, whichSync, yamlScalar } from "@nodeint/migent-kernel";
5
5
  import { printAlreadyInitialized, printCreated, printError, printInitConflicts, } from "../display.js";
6
6
  import { cliHooks } from "../hooks.js";
7
7
  import { runDoctor } from "./doctor.js";
8
+ import { installSkill } from "./skill.js";
8
9
  import { acceptedOptions, adapterMap, asCatalog, detected, knownModel, loadCatalog, loadOptionValues, parseOptions, requireAdapter, runProviderCommand, } from "../provider.js";
9
10
  export const PRESETS = ["implement", "plan"];
10
11
  export async function runInit(workspace, options = {}) {
11
12
  const provider = options.provider ?? null;
12
13
  const model = options.model ?? null;
13
14
  const preset = options.preset ?? "implement";
15
+ const skill = options.skill === true;
14
16
  const interactive = options.interactive ?? false;
15
17
  const chosen = options.adapters ?? adapterMap();
16
18
  const resolve = options.which ?? cliHooks.which ?? whichSync;
@@ -36,6 +38,8 @@ export async function runInit(workspace, options = {}) {
36
38
  const classified = classify(workspace, chosen, resolve);
37
39
  if (classified.state === "ready") {
38
40
  printAlreadyInitialized();
41
+ if (skill)
42
+ return installSkill(workspace);
39
43
  return 0;
40
44
  }
41
45
  if (classified.state === "conflict") {
@@ -43,14 +47,11 @@ export async function runInit(workspace, options = {}) {
43
47
  return 1;
44
48
  }
45
49
  let primary;
46
- let reviewer;
47
50
  try {
48
- [primary, reviewer] = await choices(chosen, resolve, prompt, {
51
+ primary = await choices(chosen, resolve, prompt, {
49
52
  provider,
50
53
  model,
51
54
  options: parseOptions(optionPairs),
52
- preset,
53
- interactive,
54
55
  runCommand: execute,
55
56
  });
56
57
  }
@@ -58,7 +59,19 @@ export async function runInit(workspace, options = {}) {
58
59
  printError(error instanceof Error ? error.message : String(error));
59
60
  return 2;
60
61
  }
61
- const paths = writeProject(workspace, preset, primary, reviewer);
62
+ let install = skill;
63
+ if (!install && interactive) {
64
+ try {
65
+ install = await prompt.confirm("Install the Migent skill in .agents/skills/migent?");
66
+ }
67
+ catch (error) {
68
+ printError(error instanceof Error ? error.message : String(error));
69
+ return 2;
70
+ }
71
+ }
72
+ if (install && installSkill(workspace) !== 0)
73
+ return 1;
74
+ const paths = writeProject(workspace, preset, primary);
62
75
  printCreated(paths, `migent start ${preset} --task "..."`);
63
76
  return runDoctor(workspace, { which: resolve });
64
77
  }
@@ -87,19 +100,7 @@ async function choices(adapters, which, prompt, args) {
87
100
  if (model.trim() === "")
88
101
  throw new Error("Model is required.");
89
102
  const primary = { provider, model: model.trim(), options: stored };
90
- if (args.preset !== "plan" || !args.interactive)
91
- return [primary, null];
92
- if (await prompt.confirm("Use the default model for both planner and reviewer?"))
93
- return [primary, null];
94
- const rows = detected(adapters, which);
95
- const reviewerProvider = await prompt.selectProvider(rows, "Reviewer provider");
96
- const reviewerAdapter = adapters[reviewerProvider];
97
- if (reviewerAdapter === undefined)
98
- throw new Error(`Unknown provider: ${reviewerProvider}.`);
99
- const reviewerCatalog = await loadCatalog(reviewerAdapter, which, args.runCommand);
100
- const reviewerModel = (await prompt.selectModel(reviewerProvider, reviewerCatalog, "Reviewer model")).trim();
101
- const reviewerOptions = await promptOptions(reviewerAdapter, reviewerModel, reviewerCatalog, which, args.runCommand, prompt);
102
- return [primary, { provider: reviewerProvider, model: reviewerModel, options: reviewerOptions }];
103
+ return primary;
103
104
  }
104
105
  function classify(workspace, adapters, which) {
105
106
  const root = path.join(workspace, ".migent");
@@ -133,27 +134,23 @@ function classify(workspace, adapters, which) {
133
134
  }
134
135
  return { state: "conflict", conflicts: owned };
135
136
  }
136
- function writeProject(workspace, preset, primary, reviewer) {
137
+ function writeProject(workspace, preset, primary) {
137
138
  const root = path.join(workspace, ".migent");
138
139
  const workflows = path.join(root, "workflows");
139
140
  mkdirSync(workflows, { recursive: true });
140
- writeFileSync(path.join(root, "config.yaml"), renderConfig(preset, primary, reviewer), "utf8");
141
+ writeFileSync(path.join(root, "config.yaml"), renderConfig(preset, primary), "utf8");
141
142
  const workflowName = `${preset}.yaml`;
142
143
  writeFileSync(path.join(workflows, workflowName), renderWorkflow(preset), "utf8");
143
144
  writeFileSync(path.join(root, ".gitignore"), "sessions/\n", "utf8");
144
145
  return [".migent/config.yaml", `.migent/workflows/${workflowName}`, ".migent/.gitignore"];
145
146
  }
146
- function renderConfig(preset, primary, reviewer) {
147
+ function renderConfig(preset, primary) {
147
148
  const models = [["default", primary]];
148
149
  let roles;
149
150
  if (preset === "implement")
150
151
  roles = [["developer", "default"]];
151
- else if (reviewer === null)
152
+ else
152
153
  roles = [["planner", "default"], ["reviewer", "default"]];
153
- else {
154
- models.push(["review", reviewer]);
155
- roles = [["planner", "default"], ["reviewer", "review"]];
156
- }
157
154
  const lines = ["schema_version: 1", "models:"];
158
155
  for (const [name, choice] of models) {
159
156
  lines.push(` ${name}:`, ` provider: ${yamlScalar(choice.provider)}`, ` model: ${yamlScalar(choice.model)}`);
package/dist/program.js CHANGED
@@ -120,6 +120,7 @@ export function createProgram(status) {
120
120
  .option("--model <model>", "Model id for the default model. Pass with --provider.")
121
121
  .option("--option <pair>", "KEY=VALUE stored under models.*.options.", collect, [])
122
122
  .option("--preset <preset>", "Workflow to create: implement or plan. Default: implement.", "implement")
123
+ .option("--skill", "Install the Migent skill at .agents/skills/migent.")
123
124
  .action((options) => settle(status, () => {
124
125
  const provider = optionalText(options.provider);
125
126
  const model = optionalText(options.model);
@@ -129,6 +130,7 @@ export function createProgram(status) {
129
130
  model,
130
131
  options: stringList(options.option),
131
132
  preset: typeof options.preset === "string" ? options.preset : "implement",
133
+ skill: options.skill === true,
132
134
  interactive,
133
135
  });
134
136
  }));
@@ -1,5 +1,5 @@
1
1
  import { ModelCatalog } from "@nodeint/migent-adapters";
2
- import type { AgentAdapter, ProviderOption } from "@nodeint/migent-kernel";
2
+ import { type AgentAdapter, type ProviderOption } from "@nodeint/migent-kernel";
3
3
  export interface CatalogAdapter extends AgentAdapter {
4
4
  modelCatalogCommand(): string[];
5
5
  parseModelCatalog(stdout: string): ModelCatalog;
package/dist/provider.js CHANGED
@@ -1,5 +1,5 @@
1
- import { spawnSync } from "node:child_process";
2
1
  import { ModelCatalog, defaultAdapters } from "@nodeint/migent-adapters";
2
+ import { spawnProviderSync } from "@nodeint/migent-kernel";
3
3
  export class ProviderCommandFailed extends Error {
4
4
  }
5
5
  export function adapterMap() {
@@ -124,7 +124,7 @@ export function runProviderCommand(argv) {
124
124
  const [command, ...args] = argv;
125
125
  if (command === undefined)
126
126
  throw new ProviderCommandFailed("Provider command is empty.");
127
- const completed = spawnSync(command, args, { encoding: "utf8", timeout: 60_000 });
127
+ const completed = spawnProviderSync(command, args, { encoding: "utf8", timeout: 60_000, windowsHide: true });
128
128
  if (completed.error) {
129
129
  throw new Error(completed.error.message);
130
130
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nodeint/migent",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Compose AI coding agents into repeatable engineering workflows.",
5
5
  "keywords": [
6
6
  "ai",
@@ -38,18 +38,14 @@
38
38
  "engines": {
39
39
  "node": ">=22"
40
40
  },
41
- "os": [
42
- "darwin",
43
- "linux"
44
- ],
45
41
  "publishConfig": {
46
42
  "access": "public"
47
43
  },
48
44
  "dependencies": {
49
45
  "@clack/prompts": "^1.8.1",
50
- "@nodeint/migent-adapters": "0.1.2",
51
- "@nodeint/migent-kernel": "0.1.2",
52
- "@nodeint/migent-registry": "0.1.2",
46
+ "@nodeint/migent-adapters": "0.1.4",
47
+ "@nodeint/migent-kernel": "0.1.4",
48
+ "@nodeint/migent-registry": "0.1.4",
53
49
  "commander": "^14.0.2",
54
50
  "picocolors": "^1.1.1"
55
51
  },