@allocator-one/harness-cli 1.15.0 → 1.15.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 +53 -11
- package/dist/chunk-FQWV5MIC.js +73 -0
- package/dist/{chunk-I2S2JVCQ.js → chunk-L2OWOZ4N.js} +240 -63
- package/dist/cli.js +185 -113
- package/dist/{login-page-UVUKFFTT.js → login-page-KGEJFFXR.js} +12 -5
- package/dist/{server-O7CX2ZCC.js → server-KVRQBVXI.js} +57 -12
- package/package.json +1 -1
- package/spec/openapi.json +1098 -293
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ACTIVITY_MAX_LIMIT,
|
|
4
|
-
|
|
4
|
+
BUDGET_MAX_DOLLARS,
|
|
5
5
|
CONDITION_KINDS,
|
|
6
6
|
Client,
|
|
7
7
|
GATE_OWNER_ROLES,
|
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
JOB_STATES,
|
|
12
12
|
JOB_STATUS_ALIASES,
|
|
13
13
|
MAX_IDEMPOTENCY_KEY_BYTES,
|
|
14
|
+
MCP_SURFACE,
|
|
15
|
+
OUTCOME_MAX_CHARACTERS,
|
|
14
16
|
PLAN_EXECUTORS,
|
|
15
17
|
RELATION_CREATE_TYPES,
|
|
16
18
|
RELATION_UPDATE_TYPES,
|
|
@@ -61,6 +63,7 @@ import {
|
|
|
61
63
|
planHold,
|
|
62
64
|
planRelease,
|
|
63
65
|
planShow,
|
|
66
|
+
prepareRun,
|
|
64
67
|
procedureRun,
|
|
65
68
|
procedureSave,
|
|
66
69
|
procedureShow,
|
|
@@ -77,6 +80,7 @@ import {
|
|
|
77
80
|
search,
|
|
78
81
|
show,
|
|
79
82
|
skillsList,
|
|
83
|
+
startRun,
|
|
80
84
|
stateAdd,
|
|
81
85
|
stateDelete,
|
|
82
86
|
stateOrder,
|
|
@@ -92,7 +96,12 @@ import {
|
|
|
92
96
|
upload,
|
|
93
97
|
userList,
|
|
94
98
|
workflowStates
|
|
95
|
-
} from "./chunk-
|
|
99
|
+
} from "./chunk-L2OWOZ4N.js";
|
|
100
|
+
import {
|
|
101
|
+
CLI_VERSION,
|
|
102
|
+
invokedName,
|
|
103
|
+
named
|
|
104
|
+
} from "./chunk-FQWV5MIC.js";
|
|
96
105
|
|
|
97
106
|
// src/mcp/server.ts
|
|
98
107
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -102,11 +111,11 @@ var NeedsLoginError = class extends Error {
|
|
|
102
111
|
};
|
|
103
112
|
function context() {
|
|
104
113
|
const resolved = resolveConfig();
|
|
105
|
-
for (const warning of resolved.warnings) process.stderr.write(warning + "\n");
|
|
114
|
+
for (const warning of resolved.warnings) process.stderr.write(named(warning + "\n"));
|
|
106
115
|
if (resolved.kind === "error") throw new NeedsLoginError(resolved.message);
|
|
107
116
|
if (resolved.kind === "needs-login") {
|
|
108
117
|
throw new NeedsLoginError(
|
|
109
|
-
`Not signed in to ${resolved.baseUrl}. Run
|
|
118
|
+
`Not signed in to ${resolved.baseUrl}. Run \`${invokedName()} login\` in a terminal (or set HARNESS_API_TOKEN for headless use) \u2014 the MCP server never opens a browser itself.`
|
|
110
119
|
);
|
|
111
120
|
}
|
|
112
121
|
return { client: new Client(resolved.config), config: resolved.config };
|
|
@@ -122,7 +131,7 @@ async function run(work) {
|
|
|
122
131
|
const output = await work(ctx);
|
|
123
132
|
const content = [{ type: "text", text: JSON.stringify(output.json) }];
|
|
124
133
|
if (output.notice !== void 0 && output.notice !== "") {
|
|
125
|
-
content.push({ type: "text", text: output.notice.trimEnd() });
|
|
134
|
+
content.push({ type: "text", text: named(output.notice.trimEnd()) });
|
|
126
135
|
}
|
|
127
136
|
if (output.partial === true) {
|
|
128
137
|
content.push({ type: "text", text: "partial failure \u2014 inspect the JSON entries for per-item errors" });
|
|
@@ -133,10 +142,10 @@ async function run(work) {
|
|
|
133
142
|
const error = explainExpertRefusal(caught, token);
|
|
134
143
|
if (error instanceof NeedsLoginError) return toolError(error.message);
|
|
135
144
|
if (error instanceof HttpError) {
|
|
136
|
-
return toolError(`${error.message} (HTTP ${error.status})${errorDetails(error.body)}`);
|
|
145
|
+
return toolError(named(`${error.message} (HTTP ${error.status})${errorDetails(error.body)}`));
|
|
137
146
|
}
|
|
138
147
|
if (error instanceof TransportError) return toolError(`cannot reach the API: ${error.message}`);
|
|
139
|
-
if (error instanceof Error) return toolError(error.message);
|
|
148
|
+
if (error instanceof Error) return toolError(named(error.message));
|
|
140
149
|
throw error;
|
|
141
150
|
}
|
|
142
151
|
}
|
|
@@ -258,6 +267,40 @@ var OPERATOR_CONTROL_TOOLS = [
|
|
|
258
267
|
handler: (ctx, args) => jobPause(ctx, args["id"])
|
|
259
268
|
}
|
|
260
269
|
];
|
|
270
|
+
var OPERATOR_RUN_TOOLS = [
|
|
271
|
+
{
|
|
272
|
+
name: "job_start",
|
|
273
|
+
description: `Start an Operator job from an outcome, as Run as job does in Chat Mode in the app: the request is posted, attributed to the caller, in a new organization chat of theirs, and Operator takes it from there under the caller's own current rights. Returns job_id, state, workbench_url and, when a change set already awaits approval, approval_url. Approval happens in the app: give a person the approval_url; this tool never approves anything, and no tool does. Each call starts another job, so never call it again to "retry": not after a timeout, a dropped connection or a 5xx either. An "Outcome unknown" error means a job may have been started; look for it with jobs_list (mine) before calling again. Only the organization's admins may pass a budget. Follow the job with job_show.`,
|
|
274
|
+
readOnly: false,
|
|
275
|
+
destructive: false,
|
|
276
|
+
idempotent: false,
|
|
277
|
+
shape: {
|
|
278
|
+
outcome: z.string().describe(
|
|
279
|
+
`what the job should achieve, in plain language: 1 to ${OUTCOME_MAX_CHARACTERS} characters once trimmed`
|
|
280
|
+
),
|
|
281
|
+
budget: z.number().positive().max(BUDGET_MAX_DOLLARS).optional().describe(
|
|
282
|
+
`the job's budget in US dollars, at most two decimals, up to ${BUDGET_MAX_DOLLARS}; only the organization's admins may pass one`
|
|
283
|
+
),
|
|
284
|
+
skill: z.string().optional().describe("an Operator skill's invocation name, like /summarize-lps (skills_list names them)")
|
|
285
|
+
},
|
|
286
|
+
handler: async (ctx, args) => {
|
|
287
|
+
const request = prepareRun(args["outcome"], {
|
|
288
|
+
budget: args["budget"] === void 0 ? void 0 : String(args["budget"]),
|
|
289
|
+
skill: args["skill"]
|
|
290
|
+
}, MCP_SURFACE);
|
|
291
|
+
const job = await startRun(ctx, request, MCP_SURFACE);
|
|
292
|
+
return {
|
|
293
|
+
json: {
|
|
294
|
+
job_id: job.job_id,
|
|
295
|
+
state: job.state,
|
|
296
|
+
workbench_url: job.workbench_url,
|
|
297
|
+
...job.approval_url === null ? {} : { approval_url: job.approval_url }
|
|
298
|
+
},
|
|
299
|
+
human: `Started Operator job ${job.job_id}.`
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
];
|
|
261
304
|
var NOT_IDEMPOTENT = 'Not idempotent: never retry it automatically, not after a timeout or a 5xx either. An "Outcome unknown" error may have landed and says what to check before calling again; only "cannot reach the API" means the request never reached the server, so nothing changed.';
|
|
262
305
|
var OPERATOR_LIFECYCLE_TOOLS = [
|
|
263
306
|
{
|
|
@@ -499,7 +542,7 @@ var TOOLS = [
|
|
|
499
542
|
},
|
|
500
543
|
{
|
|
501
544
|
name: "comment_list",
|
|
502
|
-
description: "An issue's
|
|
545
|
+
description: "An issue's complete comment thread, oldest first. Follows every older page; pagination failures return an error, not a partial thread.",
|
|
503
546
|
readOnly: true,
|
|
504
547
|
shape: { id: identifier },
|
|
505
548
|
handler: (ctx, args) => comments(ctx, args["id"])
|
|
@@ -871,7 +914,7 @@ var TOOLS = [
|
|
|
871
914
|
// ── Plans and gates ──
|
|
872
915
|
{
|
|
873
916
|
name: "plan_create",
|
|
874
|
-
description: "Create a plan: a root issue and up to 99 steps, created in one transaction or not at all, and held until a person releases it (plan_release). Steps refer to each other by key: parent (containment) and blocked_by (dependencies). executor operator files a step in the organization's Operator team, where only the plan driver claims it; a person's step goes to its team (or the plan's). conditions are wait conditions (not_before, gate, event); a gate may carry a key (gate: <key> is shorthand) and an owner, who alone ticks it. An invalid plan writes nothing and the error lists every violation by step key. Reuse idempotency_key when retrying.",
|
|
917
|
+
description: "Create a plan: a root issue and up to 99 steps, created in one transaction or not at all, and held until a person releases it (plan_release). Steps refer to each other by key: parent (containment) and blocked_by (dependencies). executor operator files a step in the organization's Operator team, where only the plan driver claims it; a person's step goes to its team (or the plan's). conditions are wait conditions (not_before, gate, event); a gate may carry a key (gate: <key> is shorthand) and an owner, who alone ticks it. An invalid plan writes nothing and the error lists every violation by step key. Reuse idempotency_key when retrying. Once released, the changes an Operator step proposes need a person's approval in the app, as plan_release says.",
|
|
875
918
|
readOnly: false,
|
|
876
919
|
shape: {
|
|
877
920
|
team: z.string().optional().describe("team key for the root and people's steps; defaults to HARNESS_TEAM"),
|
|
@@ -889,7 +932,7 @@ var TOOLS = [
|
|
|
889
932
|
},
|
|
890
933
|
{
|
|
891
934
|
name: "plan_edit",
|
|
892
|
-
description: "Change step executors and keys (each step named by its key or issue identifier) and the plan's budgets. Editing a released step holds it until the plan is released again; a budget edit needs the plan held. Descriptions, parents and edges are edited with issue_update and relation_add/relation_rm; conditions are set at plan_create, and gate_set ticks a gate.",
|
|
935
|
+
description: "Change step executors and keys (each step named by its key or issue identifier) and the plan's budgets. Editing a released step holds it until the plan is released again; a budget edit needs the plan held. Descriptions, parents and edges are edited with issue_update and relation_add/relation_rm; conditions are set at plan_create, and gate_set ticks a gate. Once released, the changes an Operator step proposes need a person's approval in the app, as plan_release says.",
|
|
893
936
|
readOnly: false,
|
|
894
937
|
shape: {
|
|
895
938
|
id: planId,
|
|
@@ -904,7 +947,7 @@ var TOOLS = [
|
|
|
904
947
|
},
|
|
905
948
|
{
|
|
906
949
|
name: "plan_release",
|
|
907
|
-
description: "Release a held plan (or one that needs attention) as the caller: freezes its next revision and lets its ready steps run. A plan with Operator steps needs a spend budget and the caller's right to run Operator; collaborators join its plan room.",
|
|
950
|
+
description: "Release a held plan (or one that needs attention) as the caller: freezes its next revision and lets its ready steps run. A plan with Operator steps needs a spend budget and the caller's right to run Operator; collaborators join its plan room. Each Operator step runs as a job (jobs_list names its plan_step), and the changes a job proposes need a person's approval in the app: give them the job's approval_url. No tool approves.",
|
|
908
951
|
readOnly: false,
|
|
909
952
|
shape: {
|
|
910
953
|
id: planId,
|
|
@@ -927,7 +970,7 @@ var TOOLS = [
|
|
|
927
970
|
},
|
|
928
971
|
{
|
|
929
972
|
name: "gate_set",
|
|
930
|
-
description: "Satisfy (satisfied true) or un-satisfy (false) a gate wait condition on an issue, found by its key, label or condition id (condition_list and issue_show list conditions). Needs staff standing in the organization or a place in its plan's room; only an owned gate's owner ticks it, and its owner or staff untick it. Anyone else gets a 403 naming the owner. An outside expert's pxc_ credential ticks the gates it owns on a step assigned to it (assignment_list); any other step is 404.",
|
|
973
|
+
description: "Satisfy (satisfied true) or un-satisfy (false) a gate wait condition on an issue, found by its key, label or condition id (condition_list and issue_show list conditions). Needs staff standing in the organization or a place in its plan's room; only an owned gate's owner ticks it, and its owner or staff untick it. Anyone else gets a 403 naming the owner. An outside expert's pxc_ credential ticks the gates it owns on a step assigned to it (assignment_list); any other step is 404. An Operator-only login (operator-cli) is refused here, as on every tool outside Operator's, even for a person in the plan's room.",
|
|
931
974
|
readOnly: false,
|
|
932
975
|
shape: {
|
|
933
976
|
issue: identifier,
|
|
@@ -954,6 +997,8 @@ var TOOLS = [
|
|
|
954
997
|
...OPERATOR_JOB_TOOLS,
|
|
955
998
|
// ── Operator job controls (CLI-46) ──
|
|
956
999
|
...OPERATOR_CONTROL_TOOLS,
|
|
1000
|
+
// ── Operator job start (CLI-45) ──
|
|
1001
|
+
...OPERATOR_RUN_TOOLS,
|
|
957
1002
|
// ── Operator job lifecycle (CLI-47) ──
|
|
958
1003
|
...OPERATOR_LIFECYCLE_TOOLS,
|
|
959
1004
|
// ── Uploads ──
|