@agntn/harnesses 0.2.0 → 0.2.1
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 +36 -13
- package/dist/_chunks/agents.mjs +2 -30
- package/dist/_chunks/agents.mjs.map +1 -1
- package/dist/_chunks/libs/typebox.mjs +11 -8
- package/dist/_chunks/libs/typebox.mjs.map +1 -1
- package/dist/_chunks/mcp-servers.mjs +5 -34
- package/dist/_chunks/mcp-servers.mjs.map +1 -1
- package/dist/_chunks/mcp.mjs +13 -163
- package/dist/_chunks/mcp.mjs.map +1 -1
- package/dist/_chunks/output.mjs +28 -0
- package/dist/_chunks/output.mjs.map +1 -0
- package/dist/_chunks/{agents-sync.d.mts → prompt-sync.d.mts} +51 -3
- package/dist/_chunks/prompt-sync.d.mts.map +1 -0
- package/dist/_chunks/{agents-sync.mjs → prompt-sync.mjs} +517 -21
- package/dist/_chunks/prompt-sync.mjs.map +1 -0
- package/dist/_chunks/prompts.mjs +28 -0
- package/dist/_chunks/prompts.mjs.map +1 -0
- package/dist/_chunks/tool-operations.mjs +43 -10
- package/dist/_chunks/tool-operations.mjs.map +1 -1
- package/dist/_chunks/tool-schemas.d.mts +5 -0
- package/dist/_chunks/tool-schemas.d.mts.map +1 -1
- package/dist/_chunks/tool-schemas.mjs +4 -0
- package/dist/_chunks/tool-schemas.mjs.map +1 -1
- package/dist/_chunks/types.mjs +1 -1
- package/dist/_chunks/types.mjs.map +1 -1
- package/dist/cli.mjs +6 -2
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +16 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/mcp.d.mts.map +1 -1
- package/dist/mcp.mjs +176 -1
- package/dist/mcp.mjs.map +1 -0
- package/dist/tool-operations.d.mts +12 -2
- package/dist/tool-operations.d.mts.map +1 -1
- package/dist/tool-operations.mjs +2 -2
- package/dist/tool-schemas.d.mts +2 -2
- package/package.json +16 -14
- package/packages/omp/extensions/harnesses.ts +19 -1
- package/packages/pi/extensions/harnesses.ts +23 -1
- package/packages/shared/tui.ts +22 -1
- package/dist/_chunks/agents-sync.d.mts.map +0 -1
- package/dist/_chunks/agents-sync.mjs.map +0 -1
- package/dist/_chunks/mcp2.mjs +0 -17
- package/dist/_chunks/mcp2.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -24,8 +24,9 @@ The rest of it sits on [harnesses.agntn.dev](https://harnesses.agntn.dev).
|
|
|
24
24
|
- ▶️ **Headless runs with real modes.** Advisor without tools, full agent, or a native read-only sandbox. A mode the CLI cannot enforce is rejected.
|
|
25
25
|
- 🔌 **MCP across the dialects.** One master list at `~/.config/agntn/mcp.jsonc`. TOML edits keep the comments.
|
|
26
26
|
- 🔗 **One AGENTS.md behind the global files.** Symlinks, so an edit through Claude or Gemini is the same bytes.
|
|
27
|
+
- 🗂️ **One prompt folder, supported harnesses.** Markdown lives under XDG data; Gemini TOML is generated from it.
|
|
27
28
|
- 📜 **Session types when the format is stable.** JSONL, SQLite, JSON. Unstable shapes stay `unknown`.
|
|
28
|
-
- 🤖 **
|
|
29
|
+
- 🤖 **Ten tools, three doors.** MCP, Pi and OMP call the same executors.
|
|
29
30
|
|
|
30
31
|
## 📦 Install
|
|
31
32
|
|
|
@@ -72,23 +73,25 @@ harnesses run claude "review this design"
|
|
|
72
73
|
harnesses run codex --read-only "review this"
|
|
73
74
|
harnesses mcp-servers list
|
|
74
75
|
harnesses agents sync --check
|
|
76
|
+
harnesses prompts sync --check
|
|
75
77
|
```
|
|
76
78
|
|
|
77
79
|
`run` without `--tools` is the advisor. `--tools` is the full agent. `--read-only` asks the CLI for a sandbox and implies tools. Timeouts, `--cwd` and `--model` sit in the [CLI guide](https://harnesses.agntn.dev/guide/cli).
|
|
78
80
|
|
|
79
81
|
### Commands
|
|
80
82
|
|
|
81
|
-
| Command
|
|
82
|
-
|
|
|
83
|
-
| `list`
|
|
84
|
-
| `detect`
|
|
85
|
-
| `info`
|
|
86
|
-
| `paths`
|
|
87
|
-
| `models`
|
|
88
|
-
| `run`
|
|
89
|
-
| `mcp-servers`
|
|
90
|
-
| `agents sync`
|
|
91
|
-
| `
|
|
83
|
+
| Command | What it does | Example |
|
|
84
|
+
| -------------- | ------------------------------------------------------ | ------------------------------------------- |
|
|
85
|
+
| `list` | Every known harness, id and name | `harnesses list` |
|
|
86
|
+
| `detect` | Which ones are installed, with versions | `harnesses detect` |
|
|
87
|
+
| `info` | Registry entry: modes, capabilities, path templates | `harnesses info claude` |
|
|
88
|
+
| `paths` | Those templates expanded for this machine | `harnesses paths pi` |
|
|
89
|
+
| `models` | Models the harness can use, through its native listing | `harnesses models pi` |
|
|
90
|
+
| `run` | One prompt through headless mode | `harnesses run claude "review this design"` |
|
|
91
|
+
| `mcp-servers` | MCP servers across the config dialects | `harnesses mcp-servers list` |
|
|
92
|
+
| `agents sync` | Link global instructions files to one master | `harnesses agents sync --check` |
|
|
93
|
+
| `prompts sync` | Sync one Markdown prompt directory across harnesses | `harnesses prompts sync --check` |
|
|
94
|
+
| `mcp` | The MCP server on stdio | `harnesses mcp` |
|
|
92
95
|
|
|
93
96
|
`list`, `detect`, `info`, `paths` and `models` take `--json` or `--toon`. `run --json` is different: that one is the harness's own structured output.
|
|
94
97
|
|
|
@@ -109,6 +112,26 @@ await getHarness("codex").invoke("Review this patch", { readOnly: true });
|
|
|
109
112
|
|
|
110
113
|
That's most of it, really. `getHarness` wants an exact id. `detectHarness` uses env vars first, then a single project marker. `invoke()` talks to the CLI. A mode the CLI cannot run comes back as an error, not a quieter one. The rest: [Registry](https://harnesses.agntn.dev/guide/registry), [Invoke](https://harnesses.agntn.dev/guide/invoke), [MCP servers](https://harnesses.agntn.dev/guide/mcp-servers), [Instructions files](https://harnesses.agntn.dev/guide/agents-sync).
|
|
111
114
|
|
|
115
|
+
### Prompt templates
|
|
116
|
+
|
|
117
|
+
Put canonical Markdown templates in `$XDG_DATA_HOME/agntn/prompts/`, or
|
|
118
|
+
`~/.local/share/agntn/prompts/` when `XDG_DATA_HOME` is unset. Then sync every
|
|
119
|
+
supported harness:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
harnesses prompts sync --check
|
|
123
|
+
harnesses prompts sync
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Markdown harnesses receive symlinks to those files. Gemini receives generated
|
|
127
|
+
TOML commands, with `$ARGUMENTS` translated to `{{args}}`. Unmanaged files at a
|
|
128
|
+
managed name are backed up under the same XDG data tree before replacement.
|
|
129
|
+
|
|
130
|
+
`getHarness("pi").promptTemplates` still lists every verified reusable prompt
|
|
131
|
+
location. `promptTemplateSyncTarget` is the single stable user destination the
|
|
132
|
+
sync owns for that harness. Formats, frontmatter and CLI limits are in the
|
|
133
|
+
[registry guide](https://harnesses.agntn.dev/guide/registry#prompt-templates).
|
|
134
|
+
|
|
112
135
|
## 🗺️ Harnesses
|
|
113
136
|
|
|
114
137
|
| ID | Name | Project skills |
|
|
@@ -145,7 +168,7 @@ omp install @agntn/harnesses
|
|
|
145
168
|
}
|
|
146
169
|
```
|
|
147
170
|
|
|
148
|
-
|
|
171
|
+
Ten tools, the same ten on MCP, Pi and OMP. `harnesses_detect`, `harnesses_info` and `harnesses_mcp_list` only read. `harnesses_run` is the one that can spend tokens. `tools` is required, so the model has to pick advisor or agent. What each call returns is on the [Agents page](https://harnesses.agntn.dev/guide/agents).
|
|
149
172
|
|
|
150
173
|
## 🚫 What this does not do
|
|
151
174
|
|
package/dist/_chunks/agents.mjs
CHANGED
|
@@ -1,36 +1,8 @@
|
|
|
1
|
-
import { isHarnessId, listHarnesses } from "./
|
|
1
|
+
import { isHarnessId, listHarnesses } from "./prompt-sync.mjs";
|
|
2
2
|
import { agentsSync } from "./tool-operations.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { formatArgs, report } from "./output.mjs";
|
|
4
4
|
import { defineCommand } from "citty";
|
|
5
5
|
import { consola } from "consola";
|
|
6
|
-
import { encode } from "@toon-format/toon";
|
|
7
|
-
const formatArgs = {
|
|
8
|
-
json: {
|
|
9
|
-
type: "boolean",
|
|
10
|
-
description: "Output as JSON"
|
|
11
|
-
},
|
|
12
|
-
toon: {
|
|
13
|
-
type: "boolean",
|
|
14
|
-
description: "Output as TOON"
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
const UNSAFE_TERMINAL_CONTROLS = /[\u0000-\u0008\u000B-\u001F\u007F-\u009F]/g;
|
|
18
|
-
function report(result, args) {
|
|
19
|
-
const sanitize = (text) => stripVTControlCharacters(text ?? "").replace(UNSAFE_TERMINAL_CONTROLS, " ");
|
|
20
|
-
if (result.isError) {
|
|
21
|
-
consola.error(sanitize(result.content[0]?.text));
|
|
22
|
-
process.exit(1);
|
|
23
|
-
}
|
|
24
|
-
if (args.json) {
|
|
25
|
-
console.log(JSON.stringify(result.details, null, 2));
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
if (args.toon) {
|
|
29
|
-
console.log(encode(result.details));
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
console.log(sanitize(result.content[0]?.text));
|
|
33
|
-
}
|
|
34
6
|
var agents_default = defineCommand({
|
|
35
7
|
meta: { description: "Manage the shared global instructions file across harnesses" },
|
|
36
8
|
subCommands: { sync: defineCommand({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.mjs","names":[
|
|
1
|
+
{"version":3,"file":"agents.mjs","names":[],"sources":["../../src/commands/agents.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { consola } from \"consola\";\nimport { isHarnessId, listHarnesses } from \"../registry.ts\";\nimport { agentsSync } from \"../tool-operations.ts\";\nimport { formatArgs, report } from \"./output.ts\";\n\nexport default defineCommand({\n meta: { description: \"Manage the shared global instructions file across harnesses\" },\n subCommands: {\n sync: defineCommand({\n meta: {\n description:\n \"Link global instructions and declared companions (agents.jsonc: source, companions, excludes)\",\n },\n args: {\n id: { type: \"positional\" as const, description: \"Harness id\", required: false },\n check: {\n type: \"boolean\" as const,\n description: \"Report what would change without writing anything\",\n },\n ...formatArgs,\n },\n run({ args }) {\n const id = args.id === undefined ? undefined : (args.id as string);\n if (id !== undefined && !isHarnessId(id)) {\n consola.error(`Unknown harness: ${id}\\nKnown: ${listHarnesses().join(\", \")}`);\n process.exit(1);\n }\n report(agentsSync(id, args.check === true), args);\n },\n }),\n },\n});\n"],"mappings":";;;;;AAMA,IAAA,iBAAe,cAAc;CAC3B,MAAM,EAAE,aAAa,8DAA8D;CACnF,aAAa,EACX,MAAM,cAAc;EAClB,MAAM,EACJ,aACE,gGACJ;EACA,MAAM;GACJ,IAAI;IAAE,MAAM;IAAuB,aAAa;IAAc,UAAU;GAAM;GAC9E,OAAO;IACL,MAAM;IACN,aAAa;GACf;GACA,GAAG;EACL;EACA,IAAI,EAAE,QAAQ;GACZ,MAAM,KAAK,KAAK,OAAO,KAAA,IAAY,KAAA,IAAa,KAAK;GACrD,IAAI,OAAO,KAAA,KAAa,CAAC,YAAY,EAAE,GAAG;IACxC,QAAQ,MAAM,oBAAoB,GAAG,WAAW,cAAc,CAAC,CAAC,KAAK,IAAI,GAAG;IAC5E,QAAQ,KAAK,CAAC;GAChB;GACA,OAAO,WAAW,IAAI,KAAK,UAAU,IAAI,GAAG,IAAI;EAClD;CACF,CAAC,EACH;AACF,CAAC"}
|
|
@@ -4176,6 +4176,9 @@ function ErrorAdditionalItems(stack, context, schemaPath, instancePath, schema,
|
|
|
4176
4176
|
return IsLessThan(index, schema.items.length) || ErrorSchemaPushStack(stack, context, nextSchemaPath, nextInstancePath, schema.additionalItems, item) && context.AddIndex(index);
|
|
4177
4177
|
});
|
|
4178
4178
|
}
|
|
4179
|
+
function EncodeFragment(fragment) {
|
|
4180
|
+
return fragment.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
4181
|
+
}
|
|
4179
4182
|
function UnicodeRegExp(pattern) {
|
|
4180
4183
|
return new RegExp(pattern, "u");
|
|
4181
4184
|
}
|
|
@@ -4199,7 +4202,7 @@ function ErrorAdditionalProperties(stack, context, schemaPath, instancePath, sch
|
|
|
4199
4202
|
const additionalProperties = [];
|
|
4200
4203
|
return EveryAll(Keys(value), 0, (key, _index) => {
|
|
4201
4204
|
const nextSchemaPath = `${schemaPath}/additionalProperties`;
|
|
4202
|
-
const nextInstancePath = `${instancePath}/${key}`;
|
|
4205
|
+
const nextInstancePath = `${instancePath}/${EncodeFragment(key)}`;
|
|
4203
4206
|
const isAdditionalProperty = regexp.test(key) || ErrorSchemaPushStack(stack, context, nextSchemaPath, nextInstancePath, schema.additionalProperties, value[key]) && context.AddKey(key);
|
|
4204
4207
|
if (!isAdditionalProperty) additionalProperties.push(key);
|
|
4205
4208
|
return isAdditionalProperty;
|
|
@@ -4278,7 +4281,7 @@ function CheckDependencies(stack, context, schema, value) {
|
|
|
4278
4281
|
function ErrorDependencies(stack, context, schemaPath, instancePath, schema, value) {
|
|
4279
4282
|
const isLength = IsEqual(Keys(value).length, 0);
|
|
4280
4283
|
const isEvery = EveryAll(Entries(schema.dependencies), 0, ([key, schema]) => {
|
|
4281
|
-
const nextSchemaPath = `${schemaPath}/dependencies/${key}`;
|
|
4284
|
+
const nextSchemaPath = `${schemaPath}/dependencies/${EncodeFragment(key)}`;
|
|
4282
4285
|
return !HasPropertyKey(value, key) || (IsArray$1(schema) ? schema.every((dependency) => HasPropertyKey(value, dependency) || context.AddError("dependencies", schemaPath, instancePath, {
|
|
4283
4286
|
property: key,
|
|
4284
4287
|
dependencies: schema
|
|
@@ -4313,7 +4316,7 @@ function CheckDependentSchemas(stack, context, schema, value) {
|
|
|
4313
4316
|
function ErrorDependentSchemas(stack, context, schemaPath, instancePath, schema, value) {
|
|
4314
4317
|
const isLength = IsEqual(Keys(value).length, 0);
|
|
4315
4318
|
const isEvery = EveryAll(Entries(schema.dependentSchemas), 0, ([key, schema]) => {
|
|
4316
|
-
const nextSchemaPath = `${schemaPath}/dependentSchemas/${key}`;
|
|
4319
|
+
const nextSchemaPath = `${schemaPath}/dependentSchemas/${EncodeFragment(key)}`;
|
|
4317
4320
|
return !HasPropertyKey(value, key) || ErrorSchema(stack, context, nextSchemaPath, instancePath, schema, value);
|
|
4318
4321
|
});
|
|
4319
4322
|
return isLength || isEvery;
|
|
@@ -5167,10 +5170,10 @@ function CheckPatternProperties(stack, context, schema, value) {
|
|
|
5167
5170
|
}
|
|
5168
5171
|
function ErrorPatternProperties(stack, context, schemaPath, instancePath, schema, value) {
|
|
5169
5172
|
return EveryAll(Entries(schema.patternProperties), 0, ([pattern, schema]) => {
|
|
5170
|
-
const nextSchemaPath = `${schemaPath}/patternProperties/${pattern}`;
|
|
5173
|
+
const nextSchemaPath = `${schemaPath}/patternProperties/${EncodeFragment(pattern)}`;
|
|
5171
5174
|
const regexp = UnicodeRegExp(pattern);
|
|
5172
5175
|
return EveryAll(Entries(value), 0, ([key, value]) => {
|
|
5173
|
-
const nextInstancePath = `${instancePath}/${key}`;
|
|
5176
|
+
const nextInstancePath = `${instancePath}/${EncodeFragment(key)}`;
|
|
5174
5177
|
return !regexp.test(key) || ErrorSchemaPushStack(stack, context, nextSchemaPath, nextInstancePath, schema, value) && context.AddKey(key);
|
|
5175
5178
|
});
|
|
5176
5179
|
});
|
|
@@ -5203,8 +5206,8 @@ function CheckProperties(stack, context, schema, value) {
|
|
|
5203
5206
|
function ErrorProperties(stack, context, schemaPath, instancePath, schema, value) {
|
|
5204
5207
|
const required = IsRequired(schema) ? schema.required : [];
|
|
5205
5208
|
return EveryAll(Entries(schema.properties), 0, ([key, schema]) => {
|
|
5206
|
-
const nextSchemaPath = `${schemaPath}/properties/${key}`;
|
|
5207
|
-
const nextInstancePath = `${instancePath}/${key}`;
|
|
5209
|
+
const nextSchemaPath = `${schemaPath}/properties/${EncodeFragment(key)}`;
|
|
5210
|
+
const nextInstancePath = `${instancePath}/${EncodeFragment(key)}`;
|
|
5208
5211
|
const isProperty = () => !HasPropertyKey(value, key) || ErrorSchemaPushStack(stack, context, nextSchemaPath, nextInstancePath, schema, value[key]) && context.AddKey(key);
|
|
5209
5212
|
return IsExactOptional(required, key) ? isProperty() : InexactOptionalCheck(value, key) || isProperty();
|
|
5210
5213
|
});
|
|
@@ -5215,7 +5218,7 @@ function CheckPropertyNames(stack, context, schema, value) {
|
|
|
5215
5218
|
function ErrorPropertyNames(stack, context, schemaPath, instancePath, schema, value) {
|
|
5216
5219
|
const propertyNames = [];
|
|
5217
5220
|
return EveryAll(Keys(value), 0, (key, _index) => {
|
|
5218
|
-
const nextInstancePath = `${instancePath}/${key}`;
|
|
5221
|
+
const nextInstancePath = `${instancePath}/${EncodeFragment(key)}`;
|
|
5219
5222
|
const isPropertyName = ErrorSchema(stack, context, `${schemaPath}/propertyNames`, nextInstancePath, schema.propertyNames, key);
|
|
5220
5223
|
if (!isPropertyName) propertyNames.push(key);
|
|
5221
5224
|
return isPropertyName;
|