@integrity-labs/agt-cli 0.28.456 → 0.28.457

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.
@@ -29,7 +29,7 @@ import {
29
29
  resolveConnectivityProbe,
30
30
  worseConnectivityOutcome,
31
31
  wrapScheduledTaskPrompt
32
- } from "./chunk-UIUYOGPK.js";
32
+ } from "./chunk-QFBCK4ZH.js";
33
33
  import {
34
34
  parsePsRows
35
35
  } from "./chunk-XWVM4KPK.js";
@@ -4910,7 +4910,7 @@ function requireHost() {
4910
4910
  }
4911
4911
 
4912
4912
  // src/lib/api-client.ts
4913
- var agtCliVersion = true ? "0.28.456" : "dev";
4913
+ var agtCliVersion = true ? "0.28.457" : "dev";
4914
4914
  var lastConfigHash = null;
4915
4915
  function setConfigHash(hash) {
4916
4916
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -7411,4 +7411,4 @@ export {
7411
7411
  managerInstallSystemUnitCommand,
7412
7412
  managerUninstallSystemUnitCommand
7413
7413
  };
7414
- //# sourceMappingURL=chunk-FNEUIWJJ.js.map
7414
+ //# sourceMappingURL=chunk-WMGMLOPB.js.map
@@ -100,7 +100,7 @@ async function spawnPairSession(session) {
100
100
  return { ok: true };
101
101
  } catch {
102
102
  }
103
- const { resolveClaudeBinary } = await import("./persistent-session-Z2UQ4VVF.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-LEWM6BKO.js");
104
104
  const claudeBin = resolveClaudeBinary();
105
105
  const pairEnv = {
106
106
  ...process.env,
@@ -373,4 +373,4 @@ export {
373
373
  startClaudePair,
374
374
  submitClaudePairCode
375
375
  };
376
- //# sourceMappingURL=claude-pair-runtime-PHAR4IF4.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-QNOUSTW3.js.map
@@ -42,7 +42,7 @@ import {
42
42
  resolveEffectivePinRaw,
43
43
  safeWriteJsonAtomic,
44
44
  setConfigHash
45
- } from "../chunk-FNEUIWJJ.js";
45
+ } from "../chunk-WMGMLOPB.js";
46
46
  import {
47
47
  getProjectDir as getProjectDir2,
48
48
  getReadyTasks,
@@ -164,7 +164,7 @@ import {
164
164
  toOpencodeModel,
165
165
  transcriptActivityAgeSeconds,
166
166
  writeEgressAllowlist
167
- } from "../chunk-UIUYOGPK.js";
167
+ } from "../chunk-QFBCK4ZH.js";
168
168
  import {
169
169
  reapOrphanChannelMcps
170
170
  } from "../chunk-XWVM4KPK.js";
@@ -9949,7 +9949,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
9949
9949
  var lastVersionCheckAt = 0;
9950
9950
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
9951
9951
  var lastResponsivenessProbeAt = 0;
9952
- var agtCliVersion = true ? "0.28.456" : "dev";
9952
+ var agtCliVersion = true ? "0.28.457" : "dev";
9953
9953
  function resolveBrewPath(execFileSync2) {
9954
9954
  try {
9955
9955
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -11110,7 +11110,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
11110
11110
  if (codeNames.length === 0) return;
11111
11111
  void (async () => {
11112
11112
  try {
11113
- const { collectDiagnostics } = await import("../persistent-session-Z2UQ4VVF.js");
11113
+ const { collectDiagnostics } = await import("../persistent-session-LEWM6BKO.js");
11114
11114
  await api.post("/host/heartbeat", {
11115
11115
  host_id: hostId,
11116
11116
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor)
@@ -11217,7 +11217,7 @@ async function pollCycle() {
11217
11217
  }
11218
11218
  try {
11219
11219
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
11220
- const { collectDiagnostics } = await import("../persistent-session-Z2UQ4VVF.js");
11220
+ const { collectDiagnostics } = await import("../persistent-session-LEWM6BKO.js");
11221
11221
  const diagCodeNames = [...agentState.persistentSessionAgents];
11222
11222
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor) : void 0;
11223
11223
  let tailscaleHostname;
@@ -11331,7 +11331,7 @@ async function pollCycle() {
11331
11331
  collectResponsivenessProbes,
11332
11332
  collectPanelessActivityProbes,
11333
11333
  getResponsivenessIntervalMs
11334
- } = await import("../responsiveness-probe-WCF2QEVT.js");
11334
+ } = await import("../responsiveness-probe-U6DPVIDD.js");
11335
11335
  const probeIntervalMs = getResponsivenessIntervalMs();
11336
11336
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
11337
11337
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -11395,7 +11395,7 @@ async function pollCycle() {
11395
11395
  collectResponsivenessProbes,
11396
11396
  livePendingInboundOldestAgeSeconds,
11397
11397
  parkPendingInbound
11398
- } = await import("../responsiveness-probe-WCF2QEVT.js");
11398
+ } = await import("../responsiveness-probe-U6DPVIDD.js");
11399
11399
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
11400
11400
  const wedgeNow = /* @__PURE__ */ new Date();
11401
11401
  const liveAgents = agentState.persistentSessionAgents;
@@ -14767,7 +14767,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
14767
14767
  void api.post("/host/restart-ack", { host_id: hostId, agent_id: agentId, restart_requested_at: requestedAt }).catch((err) => log(`[restart-lane] ack failed for '${codeName}': ${err.message}`));
14768
14768
  void (async () => {
14769
14769
  try {
14770
- const { collectDiagnostics } = await import("../persistent-session-Z2UQ4VVF.js");
14770
+ const { collectDiagnostics } = await import("../persistent-session-LEWM6BKO.js");
14771
14771
  await api.post("/host/heartbeat", {
14772
14772
  host_id: hostId,
14773
14773
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor)
@@ -14817,7 +14817,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
14817
14817
  }
14818
14818
  try {
14819
14819
  const hostId = await getHostId();
14820
- const { collectDiagnostics } = await import("../persistent-session-Z2UQ4VVF.js");
14820
+ const { collectDiagnostics } = await import("../persistent-session-LEWM6BKO.js");
14821
14821
  await api.post("/host/heartbeat", {
14822
14822
  host_id: hostId,
14823
14823
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor)
@@ -15270,7 +15270,7 @@ async function processClaudePairSessions(agents) {
15270
15270
  killPairSession,
15271
15271
  pairTmuxSession,
15272
15272
  finalizeClaudePairOnboarding
15273
- } = await import("../claude-pair-runtime-PHAR4IF4.js");
15273
+ } = await import("../claude-pair-runtime-QNOUSTW3.js");
15274
15274
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
15275
15275
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
15276
15276
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -31704,6 +31704,12 @@ var integration_metadata_v1_default = {
31704
31704
  description: "Optional query-string shape with `{arg}` placeholders.",
31705
31705
  additionalProperties: { type: "string" }
31706
31706
  },
31707
+ headers_template: {
31708
+ type: "object",
31709
+ description: 'Optional request-header shape with `{arg}` placeholders (e.g. `{ "x-origami-project": "{project_id}" }`). A header whose template resolves to empty is dropped rather than sent blank, and args consumed only by a header template are excluded from a `{$body}` expansion.',
31710
+ propertyNames: { pattern: "^[A-Za-z0-9!#$%&'*+.^_`|~-]+$" },
31711
+ additionalProperties: { type: "string" }
31712
+ },
31707
31713
  idempotency_key_header: {
31708
31714
  type: "string",
31709
31715
  minLength: 1,
@@ -37203,6 +37203,12 @@ var integration_metadata_v1_default = {
37203
37203
  description: "Optional query-string shape with `{arg}` placeholders.",
37204
37204
  additionalProperties: { type: "string" }
37205
37205
  },
37206
+ headers_template: {
37207
+ type: "object",
37208
+ description: 'Optional request-header shape with `{arg}` placeholders (e.g. `{ "x-origami-project": "{project_id}" }`). A header whose template resolves to empty is dropped rather than sent blank, and args consumed only by a header template are excluded from a `{$body}` expansion.',
37209
+ propertyNames: { pattern: "^[A-Za-z0-9!#$%&'*+.^_`|~-]+$" },
37210
+ additionalProperties: { type: "string" }
37211
+ },
37206
37212
  idempotency_key_header: {
37207
37213
  type: "string",
37208
37214
  minLength: 1,
@@ -37249,7 +37255,7 @@ var FIXED_SECONDS = {
37249
37255
  var PLACEHOLDER_RE = /\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g;
37250
37256
  function buildHttpRequest(input) {
37251
37257
  const { tool, args, baseUrl, bearerToken, requestId, extraHeaders } = input;
37252
- const { method, path_template, query_template, body_template, idempotency_key_header } = tool.http;
37258
+ const { method, path_template, query_template, headers_template, body_template, idempotency_key_header } = tool.http;
37253
37259
  const path = templatePath(path_template, args);
37254
37260
  const query = query_template ? buildQueryString(query_template, args) : "";
37255
37261
  const url2 = joinUrl(baseUrl, path) + query;
@@ -37263,9 +37269,17 @@ function buildHttpRequest(input) {
37263
37269
  const headerName = idempotency_key_header ?? "Idempotency-Key";
37264
37270
  headers[headerName] = requestId;
37265
37271
  }
37272
+ if (headers_template) {
37273
+ const reserved = /* @__PURE__ */ new Set([
37274
+ ...RESERVED_HEADER_NAMES,
37275
+ (idempotency_key_header ?? "Idempotency-Key").toLowerCase()
37276
+ ]);
37277
+ Object.assign(headers, buildTemplatedHeaders(headers_template, args, reserved));
37278
+ }
37266
37279
  let body;
37267
37280
  if (method !== "GET" && body_template !== void 0) {
37268
- const expanded = expandBodyTemplate(body_template, args);
37281
+ const bodyArgs = body_template === "{$body}" && headers_template ? omitKeys(args, headerOnlyPlaceholders(headers_template, tool.http)) : args;
37282
+ const expanded = expandBodyTemplate(body_template, bodyArgs);
37269
37283
  body = JSON.stringify(expanded);
37270
37284
  headers["Content-Type"] = "application/json";
37271
37285
  }
@@ -37274,6 +37288,65 @@ function buildHttpRequest(input) {
37274
37288
  }
37275
37289
  return { url: url2, method, headers, body };
37276
37290
  }
37291
+ var RESERVED_HEADER_NAMES = /* @__PURE__ */ new Set(["authorization", "accept", "content-type"]);
37292
+ function buildTemplatedHeaders(template, args, reservedNames) {
37293
+ const out = {};
37294
+ for (const [headerName, valueTemplate] of Object.entries(template)) {
37295
+ if (!isValidHeaderName(headerName)) {
37296
+ throw new TemplateError(`invalid header name in headers_template: ${headerName}`);
37297
+ }
37298
+ if (reservedNames.has(headerName.toLowerCase())) {
37299
+ throw new TemplateError(`headers_template cannot target reserved header: ${headerName}`);
37300
+ }
37301
+ const expanded = valueTemplate.replace(PLACEHOLDER_RE, (_full, key) => {
37302
+ const v = args[key];
37303
+ if (v === void 0 || v === null)
37304
+ return "";
37305
+ if (!isScalar(v)) {
37306
+ throw new TemplateError(`header placeholder {${key}} cannot be substituted with non-scalar value`);
37307
+ }
37308
+ return String(v);
37309
+ });
37310
+ if (expanded === "")
37311
+ continue;
37312
+ if (!isValidHeaderValue(expanded)) {
37313
+ throw new TemplateError(`header ${headerName} resolved to an invalid value`);
37314
+ }
37315
+ out[headerName] = expanded;
37316
+ }
37317
+ return out;
37318
+ }
37319
+ function headerOnlyPlaceholders(headersTemplate, http) {
37320
+ const elsewhere = /* @__PURE__ */ new Set([
37321
+ ...placeholderKeys(http.path_template),
37322
+ ...Object.values(http.query_template ?? {}).flatMap(placeholderKeys)
37323
+ ]);
37324
+ const out = /* @__PURE__ */ new Set();
37325
+ for (const key of Object.values(headersTemplate).flatMap(placeholderKeys)) {
37326
+ if (!elsewhere.has(key))
37327
+ out.add(key);
37328
+ }
37329
+ return out;
37330
+ }
37331
+ function placeholderKeys(template) {
37332
+ return [...template.matchAll(PLACEHOLDER_RE)].map((m) => m[1]);
37333
+ }
37334
+ function omitKeys(args, keys) {
37335
+ if (keys.size === 0)
37336
+ return args;
37337
+ const out = {};
37338
+ for (const [k, v] of Object.entries(args)) {
37339
+ if (!keys.has(k))
37340
+ out[k] = v;
37341
+ }
37342
+ return out;
37343
+ }
37344
+ function isValidHeaderName(name) {
37345
+ return /^[A-Za-z0-9!#$%&'*+.^_`|~-]+$/.test(name);
37346
+ }
37347
+ function isValidHeaderValue(value) {
37348
+ return !/[\x00-\x1f\x7f]/.test(value);
37349
+ }
37277
37350
  function templatePath(template, args) {
37278
37351
  return template.replace(PLACEHOLDER_RE, (_full, key) => {
37279
37352
  const value = args[key];
@@ -41182,6 +41255,10 @@ var IdentityError = class extends Error {
41182
41255
  this.status = status;
41183
41256
  }
41184
41257
  };
41258
+ function nonEmpty(value) {
41259
+ const trimmed = typeof value === "string" ? value.trim() : "";
41260
+ return trimmed === "" ? null : trimmed;
41261
+ }
41185
41262
  var IdentityResolver = class {
41186
41263
  env;
41187
41264
  fetchImpl;
@@ -41209,7 +41286,10 @@ var IdentityResolver = class {
41209
41286
  return {
41210
41287
  apiKey,
41211
41288
  organizationId: this.env.ORIGAMI_ORG_ID ?? null,
41212
- teamSlug: this.env.ORIGAMI_TEAM_SLUG ?? null
41289
+ teamSlug: this.env.ORIGAMI_TEAM_SLUG ?? null,
41290
+ // Blank is absent: an empty ORIGAMI_PROJECT_ID must mean "parent org",
41291
+ // not "scope to the empty string" (which the vendor 400s on).
41292
+ projectId: nonEmpty(this.env.ORIGAMI_PROJECT_ID)
41213
41293
  };
41214
41294
  }
41215
41295
  async resolveViaBroker() {
@@ -41255,7 +41335,8 @@ var IdentityResolver = class {
41255
41335
  return {
41256
41336
  apiKey: data.access_token,
41257
41337
  organizationId: data.organization_id ?? null,
41258
- teamSlug: data.team_slug ?? null
41338
+ teamSlug: data.team_slug ?? null,
41339
+ projectId: nonEmpty(data.project_id)
41259
41340
  };
41260
41341
  }
41261
41342
  throw new IdentityError(401, "Credential fetch failed after JWT re-exchange retry");
@@ -41297,80 +41378,36 @@ var IdentityResolver = class {
41297
41378
  }
41298
41379
  };
41299
41380
 
41300
- // src/server.ts
41301
- var DEFAULT_BASE_URL = "https://origami.chat";
41302
- var VENDOR_TIMEOUT_MS = 3e4;
41303
- function errorResult(text) {
41304
- return { isError: true, content: [{ type: "text", text: `Error: ${text}` }] };
41305
- }
41306
- function buildOrigamiMcpServer(opts) {
41307
- const baseUrl = opts.baseUrl ?? DEFAULT_BASE_URL;
41308
- const fetchImpl = opts.fetchImpl ?? fetch;
41309
- const newRequestId = opts.newRequestId ?? (() => crypto.randomUUID());
41310
- const byName = new Map(opts.descriptors.map((d) => [d.name, d]));
41311
- const server = new Server(
41312
- { name: "origami", version: "0.1.0" },
41313
- { capabilities: { tools: {} } }
41314
- );
41315
- server.setRequestHandler(ListToolsRequestSchema, async () => ({
41316
- tools: opts.descriptors.map((d) => ({
41317
- name: d.name,
41318
- description: d.description,
41319
- inputSchema: d.input_schema
41320
- }))
41321
- }));
41322
- server.setRequestHandler(CallToolRequestSchema, async (req) => {
41323
- const descriptor = byName.get(req.params.name);
41324
- if (!descriptor) {
41325
- return errorResult(`unknown tool ${req.params.name}`);
41326
- }
41327
- const args = req.params.arguments ?? {};
41328
- let identity;
41329
- try {
41330
- identity = await opts.resolveIdentity();
41331
- } catch (err) {
41332
- const msg = err instanceof IdentityError ? err.message : err.message;
41333
- return errorResult(`credential resolution failed: ${msg}`);
41334
- }
41335
- const extraHeaders = {};
41336
- if (identity.organizationId) extraHeaders["X-Organization-Id"] = identity.organizationId;
41337
- if (identity.teamSlug) extraHeaders["X-Team-Slug"] = identity.teamSlug;
41338
- let prepared;
41339
- try {
41340
- prepared = buildHttpRequest({
41341
- tool: descriptor,
41342
- args,
41343
- baseUrl,
41344
- bearerToken: identity.apiKey,
41345
- requestId: newRequestId(),
41346
- extraHeaders
41347
- });
41348
- } catch (err) {
41349
- const msg = err instanceof TemplateError ? err.message : err.message;
41350
- return errorResult(msg);
41351
- }
41352
- let resp;
41353
- try {
41354
- resp = await fetchImpl(prepared.url, {
41355
- method: prepared.method,
41356
- headers: prepared.headers,
41357
- body: prepared.body,
41358
- signal: AbortSignal.timeout(VENDOR_TIMEOUT_MS)
41359
- });
41360
- } catch (err) {
41361
- return errorResult(`origami.chat fetch failed: ${err.message}`);
41362
- }
41363
- const text = await resp.text();
41364
- if (!resp.ok) {
41365
- return errorResult(`origami.chat ${resp.status}: ${text.slice(0, 400)}`);
41381
+ // src/descriptors.ts
41382
+ var PROJECT_SCOPE_HEADER = "x-origami-project";
41383
+ var PROJECT_ID_ARG = "project_id";
41384
+ var PROJECT_ID_PROPERTY = {
41385
+ type: ["string", "null"],
41386
+ description: "Optional origami project (child org) id to scope this call to - discover ids with list_projects. Omit to act on the parent org that owns the API key. If the integration has a default project configured it is applied automatically when this is omitted; pass null to override that default and act on the parent org."
41387
+ };
41388
+ function withProjectScoping(tool) {
41389
+ return {
41390
+ ...tool,
41391
+ input_schema: {
41392
+ ...tool.input_schema,
41393
+ properties: {
41394
+ ...tool.input_schema.properties,
41395
+ [PROJECT_ID_ARG]: PROJECT_ID_PROPERTY
41396
+ }
41397
+ },
41398
+ http: {
41399
+ ...tool.http,
41400
+ headers_template: {
41401
+ ...tool.http.headers_template ?? {},
41402
+ [PROJECT_SCOPE_HEADER]: `{${PROJECT_ID_ARG}}`
41403
+ }
41366
41404
  }
41367
- return { content: [{ type: "text", text: text || "{}" }] };
41368
- });
41369
- return server;
41405
+ };
41370
41406
  }
41371
-
41372
- // src/descriptors.ts
41373
- var ORIGAMI_TOOLS = [
41407
+ function supportsProjectScoping(tool) {
41408
+ return tool.http.headers_template?.[PROJECT_SCOPE_HEADER] === `{${PROJECT_ID_ARG}}`;
41409
+ }
41410
+ var ORG_SCOPED_TOOLS = [
41374
41411
  // ==========================================================================
41375
41412
  // v1 DATA PLANE
41376
41413
  // ==========================================================================
@@ -41650,6 +41687,122 @@ var ORIGAMI_TOOLS = [
41650
41687
  }
41651
41688
  }
41652
41689
  ];
41690
+ var PROJECT_TOOLS = [
41691
+ {
41692
+ name: "list_projects",
41693
+ description: "List the projects (child orgs) under the API key's parent org, newest first. Use this to discover the project id to pass as `project_id` on any other tool - without it every call resolves against the parent org, so a project's agents and tables are invisible. Cursor-paginated: pass the previous response's `nextCursor` as `cursor`; `nextCursor: null` means the last page. Optional `search` is a case-insensitive substring match on project name. Returns { object, items[{ id, name, monthlyCredits, usage{spent,reserved}, createdAt }], nextCursor }. Always acts on the parent org - `project_id` is not accepted here.",
41694
+ risk_tier: "Low",
41695
+ input_schema: {
41696
+ type: "object",
41697
+ properties: {
41698
+ cursor: { type: "string", description: "Opaque pagination cursor - the `nextCursor` from a previous page. Omit for the first page." },
41699
+ limit: { type: "integer", minimum: 1, maximum: 100, description: "Projects per page. Default 50, max 100." },
41700
+ search: { type: "string", description: "Optional case-insensitive substring match on project name." }
41701
+ }
41702
+ },
41703
+ http: {
41704
+ method: "GET",
41705
+ path_template: "/api/v2/projects",
41706
+ query_template: { cursor: "{cursor}", limit: "{limit}", search: "{search}" }
41707
+ }
41708
+ },
41709
+ {
41710
+ name: "get_project",
41711
+ description: "Fetch a single project (child org) by id: name, optional monthlyCredits budget cap, current-period usage { spent, reserved } and createdAt. Use it to confirm a project id before scoping calls to it, or to check its remaining budget. Always acts on the parent org - `project_id` is not accepted here.",
41712
+ risk_tier: "Low",
41713
+ input_schema: {
41714
+ type: "object",
41715
+ properties: {
41716
+ projectId: { type: "string", minLength: 1, description: "The project (child org) id (uuid), from list_projects." }
41717
+ },
41718
+ required: ["projectId"]
41719
+ },
41720
+ http: { method: "GET", path_template: "/api/v2/projects/{projectId}" }
41721
+ }
41722
+ ];
41723
+ var ORIGAMI_TOOLS = [
41724
+ ...ORG_SCOPED_TOOLS.map(withProjectScoping),
41725
+ ...PROJECT_TOOLS
41726
+ ];
41727
+
41728
+ // src/server.ts
41729
+ var DEFAULT_BASE_URL = "https://origami.chat";
41730
+ var VENDOR_TIMEOUT_MS = 3e4;
41731
+ function errorResult(text) {
41732
+ return { isError: true, content: [{ type: "text", text: `Error: ${text}` }] };
41733
+ }
41734
+ function resolveProjectScope(descriptor, args, defaultProjectId) {
41735
+ if (!defaultProjectId) return args;
41736
+ if (!supportsProjectScoping(descriptor)) return args;
41737
+ if (PROJECT_ID_ARG in args) return args;
41738
+ return { ...args, [PROJECT_ID_ARG]: defaultProjectId };
41739
+ }
41740
+ function buildOrigamiMcpServer(opts) {
41741
+ const baseUrl = opts.baseUrl ?? DEFAULT_BASE_URL;
41742
+ const fetchImpl = opts.fetchImpl ?? fetch;
41743
+ const newRequestId = opts.newRequestId ?? (() => crypto.randomUUID());
41744
+ const byName = new Map(opts.descriptors.map((d) => [d.name, d]));
41745
+ const server = new Server(
41746
+ { name: "origami", version: "0.1.0" },
41747
+ { capabilities: { tools: {} } }
41748
+ );
41749
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
41750
+ tools: opts.descriptors.map((d) => ({
41751
+ name: d.name,
41752
+ description: d.description,
41753
+ inputSchema: d.input_schema
41754
+ }))
41755
+ }));
41756
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
41757
+ const descriptor = byName.get(req.params.name);
41758
+ if (!descriptor) {
41759
+ return errorResult(`unknown tool ${req.params.name}`);
41760
+ }
41761
+ const args = req.params.arguments ?? {};
41762
+ let identity;
41763
+ try {
41764
+ identity = await opts.resolveIdentity();
41765
+ } catch (err) {
41766
+ const msg = err instanceof IdentityError ? err.message : err.message;
41767
+ return errorResult(`credential resolution failed: ${msg}`);
41768
+ }
41769
+ const extraHeaders = {};
41770
+ if (identity.organizationId) extraHeaders["X-Organization-Id"] = identity.organizationId;
41771
+ if (identity.teamSlug) extraHeaders["X-Team-Slug"] = identity.teamSlug;
41772
+ const scopedArgs = resolveProjectScope(descriptor, args, identity.projectId);
41773
+ let prepared;
41774
+ try {
41775
+ prepared = buildHttpRequest({
41776
+ tool: descriptor,
41777
+ args: scopedArgs,
41778
+ baseUrl,
41779
+ bearerToken: identity.apiKey,
41780
+ requestId: newRequestId(),
41781
+ extraHeaders
41782
+ });
41783
+ } catch (err) {
41784
+ const msg = err instanceof TemplateError ? err.message : err.message;
41785
+ return errorResult(msg);
41786
+ }
41787
+ let resp;
41788
+ try {
41789
+ resp = await fetchImpl(prepared.url, {
41790
+ method: prepared.method,
41791
+ headers: prepared.headers,
41792
+ body: prepared.body,
41793
+ signal: AbortSignal.timeout(VENDOR_TIMEOUT_MS)
41794
+ });
41795
+ } catch (err) {
41796
+ return errorResult(`origami.chat fetch failed: ${err.message}`);
41797
+ }
41798
+ const text = await resp.text();
41799
+ if (!resp.ok) {
41800
+ return errorResult(`origami.chat ${resp.status}: ${text.slice(0, 400)}`);
41801
+ }
41802
+ return { content: [{ type: "text", text: text || "{}" }] };
41803
+ });
41804
+ return server;
41805
+ }
41653
41806
 
41654
41807
  // src/index.ts
41655
41808
  async function main() {
@@ -31312,6 +31312,12 @@ var integration_metadata_v1_default = {
31312
31312
  description: "Optional query-string shape with `{arg}` placeholders.",
31313
31313
  additionalProperties: { type: "string" }
31314
31314
  },
31315
+ headers_template: {
31316
+ type: "object",
31317
+ description: 'Optional request-header shape with `{arg}` placeholders (e.g. `{ "x-origami-project": "{project_id}" }`). A header whose template resolves to empty is dropped rather than sent blank, and args consumed only by a header template are excluded from a `{$body}` expansion.',
31318
+ propertyNames: { pattern: "^[A-Za-z0-9!#$%&'*+.^_`|~-]+$" },
31319
+ additionalProperties: { type: "string" }
31320
+ },
31315
31321
  idempotency_key_header: {
31316
31322
  type: "string",
31317
31323
  minLength: 1,
@@ -31614,6 +31614,12 @@ var integration_metadata_v1_default = {
31614
31614
  description: "Optional query-string shape with `{arg}` placeholders.",
31615
31615
  additionalProperties: { type: "string" }
31616
31616
  },
31617
+ headers_template: {
31618
+ type: "object",
31619
+ description: 'Optional request-header shape with `{arg}` placeholders (e.g. `{ "x-origami-project": "{project_id}" }`). A header whose template resolves to empty is dropped rather than sent blank, and args consumed only by a header template are excluded from a `{$body}` expansion.',
31620
+ propertyNames: { pattern: "^[A-Za-z0-9!#$%&'*+.^_`|~-]+$" },
31621
+ additionalProperties: { type: "string" }
31622
+ },
31617
31623
  idempotency_key_header: {
31618
31624
  type: "string",
31619
31625
  minLength: 1,
@@ -36,7 +36,7 @@ import {
36
36
  writeDirectChatSessionState,
37
37
  writeEgressAllowlist,
38
38
  writePersistentClaudeWrapper
39
- } from "./chunk-UIUYOGPK.js";
39
+ } from "./chunk-QFBCK4ZH.js";
40
40
  import "./chunk-XWVM4KPK.js";
41
41
  export {
42
42
  EGRESS_BASELINE_DOMAINS,
@@ -77,4 +77,4 @@ export {
77
77
  writeEgressAllowlist,
78
78
  writePersistentClaudeWrapper
79
79
  };
80
- //# sourceMappingURL=persistent-session-Z2UQ4VVF.js.map
80
+ //# sourceMappingURL=persistent-session-LEWM6BKO.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  paneLogPath
3
- } from "./chunk-UIUYOGPK.js";
3
+ } from "./chunk-QFBCK4ZH.js";
4
4
  import "./chunk-XWVM4KPK.js";
5
5
 
6
6
  // src/lib/responsiveness-probe.ts
@@ -528,4 +528,4 @@ export {
528
528
  readAndResetSlackReplyBindingClassifications,
529
529
  readAndResetSlackReplyTargetClassifications
530
530
  };
531
- //# sourceMappingURL=responsiveness-probe-WCF2QEVT.js.map
531
+ //# sourceMappingURL=responsiveness-probe-U6DPVIDD.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.28.456",
3
+ "version": "0.28.457",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {