@allocator-one/harness-cli 1.0.0 → 1.0.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.
@@ -108,7 +108,11 @@ var Client = class {
108
108
  async getBytes(path2) {
109
109
  const response = await this.raw("GET", path2, {});
110
110
  if (!response.ok) throw await this.toHttpError(response);
111
- return new Uint8Array(await response.arrayBuffer());
111
+ try {
112
+ return new Uint8Array(await response.arrayBuffer());
113
+ } catch (error) {
114
+ throw new TransportError(transportMessage(error));
115
+ }
112
116
  }
113
117
  /**
114
118
  * The server's API version, for `version`'s server side. The header rides
@@ -155,7 +159,12 @@ var Client = class {
155
159
  }
156
160
  async json(response) {
157
161
  if (!response.ok) throw await this.toHttpError(response);
158
- const text = await response.text();
162
+ let text;
163
+ try {
164
+ text = await response.text();
165
+ } catch (error) {
166
+ throw new TransportError(transportMessage(error));
167
+ }
159
168
  if (text === "") return { data: void 0 };
160
169
  try {
161
170
  return JSON.parse(text);
@@ -505,7 +514,7 @@ function pageCount(meta) {
505
514
  function dedupe(records) {
506
515
  const seen = /* @__PURE__ */ new Set();
507
516
  return records.filter((record) => {
508
- const key = record["id"] ?? record;
517
+ const key = record["id"] ?? JSON.stringify(record);
509
518
  if (seen.has(key)) return false;
510
519
  seen.add(key);
511
520
  return true;
@@ -1016,7 +1025,7 @@ function str2(value) {
1016
1025
  }
1017
1026
 
1018
1027
  // src/commands/extended.ts
1019
- var SAFE_ID = /^[A-Za-z0-9._-]+$/;
1028
+ var SAFE_ID = /^(?!\.{1,2}$)[A-Za-z0-9._-]+$/;
1020
1029
  function requireSafeId(kind, id) {
1021
1030
  if (!SAFE_ID.test(id)) throw new UsageError(`not a ${kind} id: ${id}`);
1022
1031
  }
@@ -1219,7 +1228,7 @@ async function linkRm(ctx, issue, idOrUrl) {
1219
1228
  const body = await ctx.client.get(`/api/v1/issues/${issue}/links`);
1220
1229
  const link = body.data.find((candidate) => candidate["id"] === idOrUrl || candidate["url"] === idOrUrl);
1221
1230
  if (link === void 0) {
1222
- throw new UsageError(`no link on ${issue} matches ${idOrUrl} (by id or exact URL)`);
1231
+ throw new CommandError(`no link on ${issue} matches ${idOrUrl} (by id or exact URL)`);
1223
1232
  }
1224
1233
  await ctx.client.delete(`/api/v1/issues/${issue}/links/${str3(link["id"])}`);
1225
1234
  return { json: { deleted: link["id"] }, human: `Removed ${clean(link["url"])} from ${issue}
@@ -1371,6 +1380,9 @@ function validateBaseUrl(baseUrl) {
1371
1380
  if (parsed.username !== "" || parsed.password !== "") {
1372
1381
  return { ok: false, message: "HARNESS_API_URL must not embed credentials (user:pass@) \u2014 use HARNESS_API_TOKEN" };
1373
1382
  }
1383
+ if (parsed.search !== "" || parsed.hash !== "") {
1384
+ return { ok: false, message: `HARNESS_API_URL must not carry a query or fragment, got: ${baseUrl}` };
1385
+ }
1374
1386
  if (parsed.protocol === "https:" && parsed.hostname !== "") return { ok: true };
1375
1387
  if (parsed.protocol === "http:") {
1376
1388
  if (["localhost", "127.0.0.1", "[::1]"].includes(parsed.hostname)) return { ok: true };
package/dist/cli.js CHANGED
@@ -53,7 +53,7 @@ import {
53
53
  version,
54
54
  workflowStates,
55
55
  writeCredentials
56
- } from "./chunk-KN5ILZSA.js";
56
+ } from "./chunk-BGBBEM3L.js";
57
57
 
58
58
  // src/cli.ts
59
59
  import { Command, CommanderError, InvalidArgumentError } from "commander";
@@ -654,7 +654,7 @@ program.command("upload").description("upload a file; prints markdown to referen
654
654
  });
655
655
  });
656
656
  program.command("mcp").description("run the MCP server over stdio (for agents)").action(async () => {
657
- const { startMcpServer } = await import("./server-PI2AZOVY.js");
657
+ const { startMcpServer } = await import("./server-YNJDA7IY.js");
658
658
  await startMcpServer();
659
659
  });
660
660
  program.command("login").description("sign in via the browser (infra.one session)").option("--url <url>", "host to sign in to").option("--no-browser", "print the URL and prompt for a pasted token instead").option("--timeout <ms>", "how long to wait for the browser callback", integer).option("--json", "emit JSON").action(async (opts) => {
@@ -4,6 +4,7 @@ import {
4
4
  Client,
5
5
  HttpError,
6
6
  TransportError,
7
+ UsageError,
7
8
  archive,
8
9
  blocked,
9
10
  close,
@@ -36,7 +37,7 @@ import {
36
37
  upload,
37
38
  userList,
38
39
  workflowStates
39
- } from "./chunk-KN5ILZSA.js";
40
+ } from "./chunk-BGBBEM3L.js";
40
41
 
41
42
  // src/mcp/server.ts
42
43
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -105,6 +106,9 @@ var TOOLS = [
105
106
  scope: z.enum(["all", "archived"]).optional()
106
107
  },
107
108
  handler: (ctx, args) => {
109
+ if (args["ready"] === true && args["blocked"] === true) {
110
+ throw new UsageError("ready and blocked are mutually exclusive \u2014 pass one, not both");
111
+ }
108
112
  if (args["ready"] === true) return ready(ctx, args);
109
113
  if (args["blocked"] === true) return blocked(ctx, args);
110
114
  return list(ctx, args);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allocator-one/harness-cli",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "CLI and MCP server for Harness, allocator.one's issue tracker",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -24,6 +24,7 @@
24
24
  "scripts": {
25
25
  "build": "tsup",
26
26
  "typecheck": "tsc --noEmit",
27
+ "pretest": "npm run build",
27
28
  "test": "vitest run",
28
29
  "codegen": "openapi-typescript spec/openapi.json -o src/generated/api.ts",
29
30
  "spec:refresh": "node scripts/spec-refresh.mjs",