@integrity-labs/agt-cli 0.28.456 → 0.28.458

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.
@@ -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,
@@ -35788,6 +35794,22 @@ var FLAG_REGISTRY = [
35788
35794
  // registry-only (ADR-0022). NOT `public`: it is resolved server-side only, so it
35789
35795
  // must never be serialized into the browser map.
35790
35796
  defaultValue: false
35797
+ },
35798
+ {
35799
+ key: "ninjafy-brand",
35800
+ description: 'Present the product under the Ninjafy brand instead of Augmented Team (ENG-8250). This is the UMBRELLA brand gate, not a one-off nav toggle: every subsequent rebrand surface (page titles, email templates, marketing-facing copy) reads THIS key rather than adding its own flag, so the whole rebrand keeps a single kill switch. First surface is the left-hand nav wordmark \u2014 ON replaces the human+robot mark and the "augmented.team" text with italic lowercase "ninjafy"; OFF renders exactly what shipped before. Scope is USER-FACING BRAND TEXT ONLY: it must never gate a code identifier, package name, env var or CLI name, which stay `Augmented`/`agt` per the CLAUDE.md naming contract (the deep code rename is workstream C of docs/runbooks/rebrand-ninjafy-migration.md and is out of scope here). Set the stage-wide default to flip a whole environment, or add a feature_flag_overrides row to pilot one organization while every other org still sees Augmented. Ships dark.',
35801
+ flagType: "boolean",
35802
+ // Declared safe value is `false`: the pre-rebrand brand. `false` is also the
35803
+ // fail-closed direction — if the flag DB is unreachable we must show the brand
35804
+ // that is currently live and contractually correct, never leak an unannounced
35805
+ // rebrand to every customer at once.
35806
+ defaultValue: false,
35807
+ // Read CLIENT-SIDE: sidebar.tsx is a "use client" component and resolves this
35808
+ // via usePublicBooleanFlag, so the key must be in the browser-exposed public
35809
+ // map. Unlike onboarding-msteams-channel above there is no wrong-org hazard —
35810
+ // the sidebar renders inside the active-org cookie's scope, which is exactly
35811
+ // the org whose brand should be shown.
35812
+ public: true
35791
35813
  }
35792
35814
  ];
35793
35815
  var REGISTRY_BY_KEY = new Map(FLAG_REGISTRY.map((definition) => [definition.key, definition]));
@@ -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];
@@ -41133,6 +41206,22 @@ var FLAG_REGISTRY = [
41133
41206
  // registry-only (ADR-0022). NOT `public`: it is resolved server-side only, so it
41134
41207
  // must never be serialized into the browser map.
41135
41208
  defaultValue: false
41209
+ },
41210
+ {
41211
+ key: "ninjafy-brand",
41212
+ description: 'Present the product under the Ninjafy brand instead of Augmented Team (ENG-8250). This is the UMBRELLA brand gate, not a one-off nav toggle: every subsequent rebrand surface (page titles, email templates, marketing-facing copy) reads THIS key rather than adding its own flag, so the whole rebrand keeps a single kill switch. First surface is the left-hand nav wordmark \u2014 ON replaces the human+robot mark and the "augmented.team" text with italic lowercase "ninjafy"; OFF renders exactly what shipped before. Scope is USER-FACING BRAND TEXT ONLY: it must never gate a code identifier, package name, env var or CLI name, which stay `Augmented`/`agt` per the CLAUDE.md naming contract (the deep code rename is workstream C of docs/runbooks/rebrand-ninjafy-migration.md and is out of scope here). Set the stage-wide default to flip a whole environment, or add a feature_flag_overrides row to pilot one organization while every other org still sees Augmented. Ships dark.',
41213
+ flagType: "boolean",
41214
+ // Declared safe value is `false`: the pre-rebrand brand. `false` is also the
41215
+ // fail-closed direction — if the flag DB is unreachable we must show the brand
41216
+ // that is currently live and contractually correct, never leak an unannounced
41217
+ // rebrand to every customer at once.
41218
+ defaultValue: false,
41219
+ // Read CLIENT-SIDE: sidebar.tsx is a "use client" component and resolves this
41220
+ // via usePublicBooleanFlag, so the key must be in the browser-exposed public
41221
+ // map. Unlike onboarding-msteams-channel above there is no wrong-org hazard —
41222
+ // the sidebar renders inside the active-org cookie's scope, which is exactly
41223
+ // the org whose brand should be shown.
41224
+ public: true
41136
41225
  }
41137
41226
  ];
41138
41227
  var REGISTRY_BY_KEY = new Map(FLAG_REGISTRY.map((definition) => [definition.key, definition]));
@@ -41182,6 +41271,10 @@ var IdentityError = class extends Error {
41182
41271
  this.status = status;
41183
41272
  }
41184
41273
  };
41274
+ function nonEmpty(value) {
41275
+ const trimmed = typeof value === "string" ? value.trim() : "";
41276
+ return trimmed === "" ? null : trimmed;
41277
+ }
41185
41278
  var IdentityResolver = class {
41186
41279
  env;
41187
41280
  fetchImpl;
@@ -41209,7 +41302,10 @@ var IdentityResolver = class {
41209
41302
  return {
41210
41303
  apiKey,
41211
41304
  organizationId: this.env.ORIGAMI_ORG_ID ?? null,
41212
- teamSlug: this.env.ORIGAMI_TEAM_SLUG ?? null
41305
+ teamSlug: this.env.ORIGAMI_TEAM_SLUG ?? null,
41306
+ // Blank is absent: an empty ORIGAMI_PROJECT_ID must mean "parent org",
41307
+ // not "scope to the empty string" (which the vendor 400s on).
41308
+ projectId: nonEmpty(this.env.ORIGAMI_PROJECT_ID)
41213
41309
  };
41214
41310
  }
41215
41311
  async resolveViaBroker() {
@@ -41255,7 +41351,8 @@ var IdentityResolver = class {
41255
41351
  return {
41256
41352
  apiKey: data.access_token,
41257
41353
  organizationId: data.organization_id ?? null,
41258
- teamSlug: data.team_slug ?? null
41354
+ teamSlug: data.team_slug ?? null,
41355
+ projectId: nonEmpty(data.project_id)
41259
41356
  };
41260
41357
  }
41261
41358
  throw new IdentityError(401, "Credential fetch failed after JWT re-exchange retry");
@@ -41297,80 +41394,36 @@ var IdentityResolver = class {
41297
41394
  }
41298
41395
  };
41299
41396
 
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)}`);
41397
+ // src/descriptors.ts
41398
+ var PROJECT_SCOPE_HEADER = "x-origami-project";
41399
+ var PROJECT_ID_ARG = "project_id";
41400
+ var PROJECT_ID_PROPERTY = {
41401
+ type: ["string", "null"],
41402
+ 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."
41403
+ };
41404
+ function withProjectScoping(tool) {
41405
+ return {
41406
+ ...tool,
41407
+ input_schema: {
41408
+ ...tool.input_schema,
41409
+ properties: {
41410
+ ...tool.input_schema.properties,
41411
+ [PROJECT_ID_ARG]: PROJECT_ID_PROPERTY
41412
+ }
41413
+ },
41414
+ http: {
41415
+ ...tool.http,
41416
+ headers_template: {
41417
+ ...tool.http.headers_template ?? {},
41418
+ [PROJECT_SCOPE_HEADER]: `{${PROJECT_ID_ARG}}`
41419
+ }
41366
41420
  }
41367
- return { content: [{ type: "text", text: text || "{}" }] };
41368
- });
41369
- return server;
41421
+ };
41370
41422
  }
41371
-
41372
- // src/descriptors.ts
41373
- var ORIGAMI_TOOLS = [
41423
+ function supportsProjectScoping(tool) {
41424
+ return tool.http.headers_template?.[PROJECT_SCOPE_HEADER] === `{${PROJECT_ID_ARG}}`;
41425
+ }
41426
+ var ORG_SCOPED_TOOLS = [
41374
41427
  // ==========================================================================
41375
41428
  // v1 DATA PLANE
41376
41429
  // ==========================================================================
@@ -41650,6 +41703,122 @@ var ORIGAMI_TOOLS = [
41650
41703
  }
41651
41704
  }
41652
41705
  ];
41706
+ var PROJECT_TOOLS = [
41707
+ {
41708
+ name: "list_projects",
41709
+ 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.",
41710
+ risk_tier: "Low",
41711
+ input_schema: {
41712
+ type: "object",
41713
+ properties: {
41714
+ cursor: { type: "string", description: "Opaque pagination cursor - the `nextCursor` from a previous page. Omit for the first page." },
41715
+ limit: { type: "integer", minimum: 1, maximum: 100, description: "Projects per page. Default 50, max 100." },
41716
+ search: { type: "string", description: "Optional case-insensitive substring match on project name." }
41717
+ }
41718
+ },
41719
+ http: {
41720
+ method: "GET",
41721
+ path_template: "/api/v2/projects",
41722
+ query_template: { cursor: "{cursor}", limit: "{limit}", search: "{search}" }
41723
+ }
41724
+ },
41725
+ {
41726
+ name: "get_project",
41727
+ 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.",
41728
+ risk_tier: "Low",
41729
+ input_schema: {
41730
+ type: "object",
41731
+ properties: {
41732
+ projectId: { type: "string", minLength: 1, description: "The project (child org) id (uuid), from list_projects." }
41733
+ },
41734
+ required: ["projectId"]
41735
+ },
41736
+ http: { method: "GET", path_template: "/api/v2/projects/{projectId}" }
41737
+ }
41738
+ ];
41739
+ var ORIGAMI_TOOLS = [
41740
+ ...ORG_SCOPED_TOOLS.map(withProjectScoping),
41741
+ ...PROJECT_TOOLS
41742
+ ];
41743
+
41744
+ // src/server.ts
41745
+ var DEFAULT_BASE_URL = "https://origami.chat";
41746
+ var VENDOR_TIMEOUT_MS = 3e4;
41747
+ function errorResult(text) {
41748
+ return { isError: true, content: [{ type: "text", text: `Error: ${text}` }] };
41749
+ }
41750
+ function resolveProjectScope(descriptor, args, defaultProjectId) {
41751
+ if (!defaultProjectId) return args;
41752
+ if (!supportsProjectScoping(descriptor)) return args;
41753
+ if (PROJECT_ID_ARG in args) return args;
41754
+ return { ...args, [PROJECT_ID_ARG]: defaultProjectId };
41755
+ }
41756
+ function buildOrigamiMcpServer(opts) {
41757
+ const baseUrl = opts.baseUrl ?? DEFAULT_BASE_URL;
41758
+ const fetchImpl = opts.fetchImpl ?? fetch;
41759
+ const newRequestId = opts.newRequestId ?? (() => crypto.randomUUID());
41760
+ const byName = new Map(opts.descriptors.map((d) => [d.name, d]));
41761
+ const server = new Server(
41762
+ { name: "origami", version: "0.1.0" },
41763
+ { capabilities: { tools: {} } }
41764
+ );
41765
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
41766
+ tools: opts.descriptors.map((d) => ({
41767
+ name: d.name,
41768
+ description: d.description,
41769
+ inputSchema: d.input_schema
41770
+ }))
41771
+ }));
41772
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
41773
+ const descriptor = byName.get(req.params.name);
41774
+ if (!descriptor) {
41775
+ return errorResult(`unknown tool ${req.params.name}`);
41776
+ }
41777
+ const args = req.params.arguments ?? {};
41778
+ let identity;
41779
+ try {
41780
+ identity = await opts.resolveIdentity();
41781
+ } catch (err) {
41782
+ const msg = err instanceof IdentityError ? err.message : err.message;
41783
+ return errorResult(`credential resolution failed: ${msg}`);
41784
+ }
41785
+ const extraHeaders = {};
41786
+ if (identity.organizationId) extraHeaders["X-Organization-Id"] = identity.organizationId;
41787
+ if (identity.teamSlug) extraHeaders["X-Team-Slug"] = identity.teamSlug;
41788
+ const scopedArgs = resolveProjectScope(descriptor, args, identity.projectId);
41789
+ let prepared;
41790
+ try {
41791
+ prepared = buildHttpRequest({
41792
+ tool: descriptor,
41793
+ args: scopedArgs,
41794
+ baseUrl,
41795
+ bearerToken: identity.apiKey,
41796
+ requestId: newRequestId(),
41797
+ extraHeaders
41798
+ });
41799
+ } catch (err) {
41800
+ const msg = err instanceof TemplateError ? err.message : err.message;
41801
+ return errorResult(msg);
41802
+ }
41803
+ let resp;
41804
+ try {
41805
+ resp = await fetchImpl(prepared.url, {
41806
+ method: prepared.method,
41807
+ headers: prepared.headers,
41808
+ body: prepared.body,
41809
+ signal: AbortSignal.timeout(VENDOR_TIMEOUT_MS)
41810
+ });
41811
+ } catch (err) {
41812
+ return errorResult(`origami.chat fetch failed: ${err.message}`);
41813
+ }
41814
+ const text = await resp.text();
41815
+ if (!resp.ok) {
41816
+ return errorResult(`origami.chat ${resp.status}: ${text.slice(0, 400)}`);
41817
+ }
41818
+ return { content: [{ type: "text", text: text || "{}" }] };
41819
+ });
41820
+ return server;
41821
+ }
41653
41822
 
41654
41823
  // src/index.ts
41655
41824
  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,
@@ -35396,6 +35402,22 @@ var FLAG_REGISTRY = [
35396
35402
  // registry-only (ADR-0022). NOT `public`: it is resolved server-side only, so it
35397
35403
  // must never be serialized into the browser map.
35398
35404
  defaultValue: false
35405
+ },
35406
+ {
35407
+ key: "ninjafy-brand",
35408
+ description: 'Present the product under the Ninjafy brand instead of Augmented Team (ENG-8250). This is the UMBRELLA brand gate, not a one-off nav toggle: every subsequent rebrand surface (page titles, email templates, marketing-facing copy) reads THIS key rather than adding its own flag, so the whole rebrand keeps a single kill switch. First surface is the left-hand nav wordmark \u2014 ON replaces the human+robot mark and the "augmented.team" text with italic lowercase "ninjafy"; OFF renders exactly what shipped before. Scope is USER-FACING BRAND TEXT ONLY: it must never gate a code identifier, package name, env var or CLI name, which stay `Augmented`/`agt` per the CLAUDE.md naming contract (the deep code rename is workstream C of docs/runbooks/rebrand-ninjafy-migration.md and is out of scope here). Set the stage-wide default to flip a whole environment, or add a feature_flag_overrides row to pilot one organization while every other org still sees Augmented. Ships dark.',
35409
+ flagType: "boolean",
35410
+ // Declared safe value is `false`: the pre-rebrand brand. `false` is also the
35411
+ // fail-closed direction — if the flag DB is unreachable we must show the brand
35412
+ // that is currently live and contractually correct, never leak an unannounced
35413
+ // rebrand to every customer at once.
35414
+ defaultValue: false,
35415
+ // Read CLIENT-SIDE: sidebar.tsx is a "use client" component and resolves this
35416
+ // via usePublicBooleanFlag, so the key must be in the browser-exposed public
35417
+ // map. Unlike onboarding-msteams-channel above there is no wrong-org hazard —
35418
+ // the sidebar renders inside the active-org cookie's scope, which is exactly
35419
+ // the org whose brand should be shown.
35420
+ public: true
35399
35421
  }
35400
35422
  ];
35401
35423
  var REGISTRY_BY_KEY = new Map(FLAG_REGISTRY.map((definition) => [definition.key, definition]));
@@ -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,
@@ -35698,6 +35704,22 @@ var FLAG_REGISTRY = [
35698
35704
  // registry-only (ADR-0022). NOT `public`: it is resolved server-side only, so it
35699
35705
  // must never be serialized into the browser map.
35700
35706
  defaultValue: false
35707
+ },
35708
+ {
35709
+ key: "ninjafy-brand",
35710
+ description: 'Present the product under the Ninjafy brand instead of Augmented Team (ENG-8250). This is the UMBRELLA brand gate, not a one-off nav toggle: every subsequent rebrand surface (page titles, email templates, marketing-facing copy) reads THIS key rather than adding its own flag, so the whole rebrand keeps a single kill switch. First surface is the left-hand nav wordmark \u2014 ON replaces the human+robot mark and the "augmented.team" text with italic lowercase "ninjafy"; OFF renders exactly what shipped before. Scope is USER-FACING BRAND TEXT ONLY: it must never gate a code identifier, package name, env var or CLI name, which stay `Augmented`/`agt` per the CLAUDE.md naming contract (the deep code rename is workstream C of docs/runbooks/rebrand-ninjafy-migration.md and is out of scope here). Set the stage-wide default to flip a whole environment, or add a feature_flag_overrides row to pilot one organization while every other org still sees Augmented. Ships dark.',
35711
+ flagType: "boolean",
35712
+ // Declared safe value is `false`: the pre-rebrand brand. `false` is also the
35713
+ // fail-closed direction — if the flag DB is unreachable we must show the brand
35714
+ // that is currently live and contractually correct, never leak an unannounced
35715
+ // rebrand to every customer at once.
35716
+ defaultValue: false,
35717
+ // Read CLIENT-SIDE: sidebar.tsx is a "use client" component and resolves this
35718
+ // via usePublicBooleanFlag, so the key must be in the browser-exposed public
35719
+ // map. Unlike onboarding-msteams-channel above there is no wrong-org hazard —
35720
+ // the sidebar renders inside the active-org cookie's scope, which is exactly
35721
+ // the org whose brand should be shown.
35722
+ public: true
35701
35723
  }
35702
35724
  ];
35703
35725
  var REGISTRY_BY_KEY = new Map(FLAG_REGISTRY.map((definition) => [definition.key, definition]));
@@ -36,7 +36,7 @@ import {
36
36
  writeDirectChatSessionState,
37
37
  writeEgressAllowlist,
38
38
  writePersistentClaudeWrapper
39
- } from "./chunk-UIUYOGPK.js";
39
+ } from "./chunk-KAIH24HZ.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-EVLWDI3I.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  paneLogPath
3
- } from "./chunk-UIUYOGPK.js";
3
+ } from "./chunk-KAIH24HZ.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-EGP2F3WD.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.458",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {