@integrity-labs/agt-cli 0.28.1111 → 0.28.1113
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/dist/bin/agt.js +5 -5
- package/dist/{chunk-4PTXGOVO.js → chunk-JX7ZXCNZ.js} +2 -2
- package/dist/{chunk-TZM6YVE7.js → chunk-OBZB6MUE.js} +105 -9
- package/dist/chunk-OBZB6MUE.js.map +1 -0
- package/dist/{chunk-2UHVPGB3.js → chunk-TXNVB3DN.js} +4 -4
- package/dist/{claude-pair-runtime-L7KXG3DD.js → claude-pair-runtime-GL67TYXC.js} +2 -2
- package/dist/lib/manager-worker.js +16 -16
- package/dist/mcp/direct-chat-channel.js +332 -14
- package/dist/mcp/index.js +340 -38
- package/dist/mcp/origami.js +104 -8
- package/dist/mcp/slack-channel.js +340 -14
- package/dist/mcp/telegram-channel.js +472 -70
- package/dist/{persistent-session-HSYN3SQ2.js → persistent-session-6KIQF4O7.js} +3 -3
- package/dist/{responsiveness-probe-MO4L5O6F.js → responsiveness-probe-GGJNITME.js} +3 -3
- package/dist/{session-auth-dead-ZKI4XCSI.js → session-auth-dead-LMCPZJ4K.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-TZM6YVE7.js.map +0 -1
- /package/dist/{chunk-4PTXGOVO.js.map → chunk-JX7ZXCNZ.js.map} +0 -0
- /package/dist/{chunk-2UHVPGB3.js.map → chunk-TXNVB3DN.js.map} +0 -0
- /package/dist/{claude-pair-runtime-L7KXG3DD.js.map → claude-pair-runtime-GL67TYXC.js.map} +0 -0
- /package/dist/{persistent-session-HSYN3SQ2.js.map → persistent-session-6KIQF4O7.js.map} +0 -0
- /package/dist/{responsiveness-probe-MO4L5O6F.js.map → responsiveness-probe-GGJNITME.js.map} +0 -0
- /package/dist/{session-auth-dead-ZKI4XCSI.js.map → session-auth-dead-LMCPZJ4K.js.map} +0 -0
package/dist/mcp/index.js
CHANGED
|
@@ -18867,7 +18867,7 @@ var require_filters = __commonJS({
|
|
|
18867
18867
|
return r.copySafeness(str, res);
|
|
18868
18868
|
}
|
|
18869
18869
|
_exports.indent = indent;
|
|
18870
|
-
function
|
|
18870
|
+
function join11(arr, del, attr) {
|
|
18871
18871
|
del = del || "";
|
|
18872
18872
|
if (attr) {
|
|
18873
18873
|
arr = lib.map(arr, function(v) {
|
|
@@ -18876,7 +18876,7 @@ var require_filters = __commonJS({
|
|
|
18876
18876
|
}
|
|
18877
18877
|
return arr.join(del);
|
|
18878
18878
|
}
|
|
18879
|
-
_exports.join =
|
|
18879
|
+
_exports.join = join11;
|
|
18880
18880
|
function last(arr) {
|
|
18881
18881
|
return arr[arr.length - 1];
|
|
18882
18882
|
}
|
|
@@ -25562,6 +25562,51 @@ var OAUTH_PROVIDERS = {
|
|
|
25562
25562
|
}
|
|
25563
25563
|
]
|
|
25564
25564
|
},
|
|
25565
|
+
"otter": {
|
|
25566
|
+
// CS-2029: Otter.ai's official MCP — remote streamable-HTTP at
|
|
25567
|
+
// https://mcp.otter.ai/mcp. Same Granola/Kajabi shape: OAuth 2.0
|
|
25568
|
+
// authorization-code with PKCE (S256) and a public client
|
|
25569
|
+
// (token_endpoint_auth_method 'none') issued via Dynamic Client
|
|
25570
|
+
// Registration (RFC 7591). Values below are taken verbatim from the
|
|
25571
|
+
// metadata, not inferred:
|
|
25572
|
+
// - https://mcp.otter.ai/.well-known/oauth-protected-resource names the
|
|
25573
|
+
// AS as https://otter.ai/ and advertises scopes profile:read,
|
|
25574
|
+
// conversations:read;
|
|
25575
|
+
// - https://otter.ai/.well-known/oauth-authorization-server gives
|
|
25576
|
+
// authorize /oauth2/authorize, token /oauth/token, revoke
|
|
25577
|
+
// /oauth/revoke_token, register /oauth/register, PKCE S256, `none`,
|
|
25578
|
+
// and the refresh_token grant.
|
|
25579
|
+
// NOTE the authorize path is /oauth2/authorize while token/revoke live
|
|
25580
|
+
// under /oauth/ — that is Otter's own split, do not "normalise" it.
|
|
25581
|
+
// The prod client was registered 2026-10-10 against /oauth/register with
|
|
25582
|
+
// scope 'profile:read conversations:read' and BOTH API callbacks,
|
|
25583
|
+
// https://api.augmented.team/... and https://api.ninjafy.com/integrations/oauth/callback,
|
|
25584
|
+
// because redirect_uri follows API_PUBLIC_URL and the ENG-11060 flip makes
|
|
25585
|
+
// the ninjafy name canonical; Otter returns no RFC 7592 handle, so a redirect
|
|
25586
|
+
// cannot be added later without a new client and a re-consent per connection.
|
|
25587
|
+
// OAUTH_OTTER_CLIENT_ID is set from its output (docs/runbooks/otter-dogfood.md). Otter advertises ONLY
|
|
25588
|
+
// read scopes, so this integration is read-only by construction: there is
|
|
25589
|
+
// no write scope to request even by mistake.
|
|
25590
|
+
definitionId: "otter",
|
|
25591
|
+
authorizeUrl: "https://otter.ai/oauth2/authorize",
|
|
25592
|
+
tokenUrl: "https://otter.ai/oauth/token",
|
|
25593
|
+
revokeUrl: "https://otter.ai/oauth/revoke_token",
|
|
25594
|
+
defaultScopes: ["profile:read", "conversations:read"],
|
|
25595
|
+
supportsRefresh: true,
|
|
25596
|
+
extraAuthorizeParams: {},
|
|
25597
|
+
clientAuthMethod: "body",
|
|
25598
|
+
pkce: "S256",
|
|
25599
|
+
publicClient: true,
|
|
25600
|
+
mcpUrl: "https://mcp.otter.ai/mcp",
|
|
25601
|
+
// Curated surface (matches the catalog seed's defined_scopes[].tools).
|
|
25602
|
+
// These are the server's three tools, all read-only. The names are
|
|
25603
|
+
// Otter's own, quoted from the tools' descriptions ("use `otter_search`
|
|
25604
|
+
// first", "call otter_get_user_info() first"), not Composio's wrapped
|
|
25605
|
+
// OTTER_AI_MCP_* slugs. An allowlisted name the server does not advertise
|
|
25606
|
+
// is logged and SKIPPED by the proxy, so confirm against the first live
|
|
25607
|
+
// tools/list after a real consent (runbook Step 3).
|
|
25608
|
+
toolAllowlist: ["otter_get_user_info", "otter_search", "otter_fetch"]
|
|
25609
|
+
},
|
|
25565
25610
|
"notion-cli": {
|
|
25566
25611
|
// Notion's public OAuth app. Tokens are workspace-scoped and long-lived —
|
|
25567
25612
|
// Notion does not issue refresh_tokens, so `supportsRefresh: false` and
|
|
@@ -26195,6 +26240,34 @@ var INTEGRATION_REGISTRY = [
|
|
|
26195
26240
|
docs_url: "https://help.kajabi.com/articles/api-integrations/connect-kajabi-to-claude-or-chatgpt",
|
|
26196
26241
|
beta: true
|
|
26197
26242
|
},
|
|
26243
|
+
{
|
|
26244
|
+
id: "otter",
|
|
26245
|
+
name: "Otter.ai",
|
|
26246
|
+
category: "knowledge",
|
|
26247
|
+
description: "Read Otter.ai meetings: search recordings by date, attendee or topic, and read summaries, action items and full speaker-attributed transcripts.",
|
|
26248
|
+
// CS-2029: same remote streamable-HTTP MCP + OAuth pattern as Granola/Kajabi.
|
|
26249
|
+
// Otter's server implements the MCP discovery chain (RFC 9728 protected-
|
|
26250
|
+
// resource metadata at mcp.otter.ai → RFC 8414 AS metadata at otter.ai →
|
|
26251
|
+
// RFC 7591 registration); auth is OAuth 2.0 authorization-code with PKCE
|
|
26252
|
+
// (S256) and a public client registered via one-time Dynamic Client
|
|
26253
|
+
// Registration (scripts/dcr-register.ts against https://otter.ai/oauth/register
|
|
26254
|
+
// → OAUTH_OTTER_CLIENT_ID, --scope 'profile:read conversations:read').
|
|
26255
|
+
// Consent is brokered by the webapp through the shared
|
|
26256
|
+
// /integrations/oauth/authorize → /callback path, and the access_token
|
|
26257
|
+
// reaches the host via the generic remote-oauth-proxy
|
|
26258
|
+
// (OAUTH_PROVIDERS.otter.mcpUrl). Read-only by construction: Otter
|
|
26259
|
+
// advertises no write scope.
|
|
26260
|
+
supported_auth_types: ["oauth2"],
|
|
26261
|
+
capabilities: [
|
|
26262
|
+
{ id: "otter:read", name: "Read Meetings & Transcripts", description: "Find recorded meetings by date, attendee, topic or title, and read their summaries, action items, outlines and full transcripts (otter_get_user_info, otter_search, otter_fetch)", access: "read" }
|
|
26263
|
+
],
|
|
26264
|
+
// Otter's own Help Center article for the MCP server (CodeRabbit, #6906). It
|
|
26265
|
+
// exists even though help.otter.ai answers 403 to non-browser clients; the
|
|
26266
|
+
// help-centre API confirmed it (title "Otter MCP Server"). The MCP endpoint
|
|
26267
|
+
// itself is a JSON-RPC URL, not a page (Obi Wan 8305072d5414).
|
|
26268
|
+
docs_url: "https://help.otter.ai/hc/en-us/articles/35287607569687-Otter-MCP-Server",
|
|
26269
|
+
beta: true
|
|
26270
|
+
},
|
|
26198
26271
|
{
|
|
26199
26272
|
id: "anchor-browser",
|
|
26200
26273
|
name: "Anchor Browser",
|
|
@@ -30673,14 +30746,37 @@ var FLAG_REGISTRY = [
|
|
|
30673
30746
|
},
|
|
30674
30747
|
{
|
|
30675
30748
|
key: "platform-maintenance-mode",
|
|
30676
|
-
description: 'Platform-wide maintenance mode (ENG-6506)
|
|
30677
|
-
flagType: "
|
|
30678
|
-
|
|
30679
|
-
//
|
|
30680
|
-
//
|
|
30681
|
-
//
|
|
30682
|
-
//
|
|
30683
|
-
|
|
30749
|
+
description: 'Platform-wide maintenance mode (ENG-6506; widened to modes by ENG-11436). off = normal operation (ships dark; channels behave exactly as today). tools-offline = every agent KEEPS conversing but every Augmented tool that WRITES to the control plane refuses with a reason, so nothing is created during a window whose database restore would discard it; reads are untouched. fleet-offline = the previous boolean-true behaviour AND the write gate: admitted human inbound gets a "we are offline for maintenance" notice instead of being dispatched, for whole-platform downtime such as DB upgrades. The modes are CUMULATIVE \u2014 fleet-offline gates writes too, because silencing channel inbound does not stop a /loop or a scheduled task filing work. Read host-side per inbound and per tool call from the flags cache (no MCP restart). (Proactive "back online" follow-up is the ENG-6508 fast-follow, not this flag.)',
|
|
30750
|
+
flagType: "enum",
|
|
30751
|
+
allowedValues: ["off", "tools-offline", "fleet-offline"],
|
|
30752
|
+
// Declared safe value is `off` (normal operation). Fail-safe direction: a
|
|
30753
|
+
// flag-DB read error or absent flag map must never silence the fleet OR take
|
|
30754
|
+
// its write tools away on its own — agents stay fully functional unless an
|
|
30755
|
+
// operator deliberately sets a mode from the admin Feature Flags page. No
|
|
30756
|
+
// envVar: net-new control, no pre-flags env gate to migrate.
|
|
30757
|
+
//
|
|
30758
|
+
// ENG-11436 widened this from a boolean rather than adding a second flag, so
|
|
30759
|
+
// there is ONE operator control whose modes are mutually exclusive by type
|
|
30760
|
+
// instead of two similar booleans with four combinations.
|
|
30761
|
+
//
|
|
30762
|
+
// The host resolver GRANDFATHERS a boolean-shaped cache value
|
|
30763
|
+
// (true -> fleet-offline, false -> off), and the DIRECTION it protects is
|
|
30764
|
+
// narrower than an earlier version of this comment claimed (Obi Wan
|
|
30765
|
+
// `e3f0d2c154b9` on #6903). It said "an older manager still writing a boolean
|
|
30766
|
+
// must not make a central flip a silent no-op". That situation cannot arise:
|
|
30767
|
+
// once this registry change deploys, normalizeFlagValue only ever yields one
|
|
30768
|
+
// of the three strings, feature-flags-host.ts writes the heartbeat map
|
|
30769
|
+
// verbatim, so no manager writes a boolean again. What grandfathering
|
|
30770
|
+
// actually covers is a NEW MCP reading a STALE PRE-DEPLOY cache that still
|
|
30771
|
+
// holds one.
|
|
30772
|
+
//
|
|
30773
|
+
// The direction that DOES happen is not handled and cannot be: an OLD MCP
|
|
30774
|
+
// reads the new string with resolveHostBooleanFlag, gets undefined, and keeps
|
|
30775
|
+
// dispatching. That is a real regression against ENG-6506 until the fleet
|
|
30776
|
+
// converges, and it is why the runbook makes convergence a deploy-order
|
|
30777
|
+
// PRECONDITION rather than offering a boolean fallback — there is none, since
|
|
30778
|
+
// an enum flag rejects `{value: true}` with a 400.
|
|
30779
|
+
defaultValue: "off",
|
|
30684
30780
|
// Flipping this takes the ENTIRE fleet offline to end users; a mis-flip is a
|
|
30685
30781
|
// platform-wide availability incident, so mutations require explicit
|
|
30686
30782
|
// confirmation (the admin flip-reach modal).
|
|
@@ -35564,8 +35660,8 @@ function renderKnowledgeBody(content) {
|
|
|
35564
35660
|
}
|
|
35565
35661
|
|
|
35566
35662
|
// src/index.ts
|
|
35567
|
-
import { homedir as
|
|
35568
|
-
import { basename, isAbsolute as isAbsolute2, join as
|
|
35663
|
+
import { homedir as homedir5 } from "os";
|
|
35664
|
+
import { basename, isAbsolute as isAbsolute2, join as join10, resolve as pathResolve, sep as sep2 } from "path";
|
|
35569
35665
|
|
|
35570
35666
|
// src/host-file-path.ts
|
|
35571
35667
|
var SKILL_BODY_PATH_MAX_BYTES = 512 * 1024;
|
|
@@ -46089,6 +46185,192 @@ var StdioServerTransport = class {
|
|
|
46089
46185
|
}
|
|
46090
46186
|
};
|
|
46091
46187
|
|
|
46188
|
+
// src/flags-cache-read.ts
|
|
46189
|
+
import { existsSync as existsSync2, readFileSync as readFileSync4 } from "fs";
|
|
46190
|
+
import { homedir as homedir2 } from "os";
|
|
46191
|
+
import { join as join6 } from "path";
|
|
46192
|
+
function defaultFlagsCachePath() {
|
|
46193
|
+
return join6(homedir2(), ".augmented", "flags-cache.json");
|
|
46194
|
+
}
|
|
46195
|
+
function envBoolean(raw) {
|
|
46196
|
+
if (raw === void 0) return void 0;
|
|
46197
|
+
const v = raw.trim().toLowerCase();
|
|
46198
|
+
if (v === "") return void 0;
|
|
46199
|
+
if (v === "1" || v === "true" || v === "yes" || v === "on") return true;
|
|
46200
|
+
if (v === "0" || v === "false" || v === "no" || v === "off") return false;
|
|
46201
|
+
return void 0;
|
|
46202
|
+
}
|
|
46203
|
+
var MAINTENANCE_FLAG_KEY = "platform-maintenance-mode";
|
|
46204
|
+
function parseMaintenanceMode(raw) {
|
|
46205
|
+
if (raw === void 0) return void 0;
|
|
46206
|
+
const v = raw.trim().toLowerCase();
|
|
46207
|
+
if (v === "") return void 0;
|
|
46208
|
+
if (v === "off" || v === "tools-offline" || v === "fleet-offline") return v;
|
|
46209
|
+
const b = envBoolean(raw);
|
|
46210
|
+
if (b === true) return "fleet-offline";
|
|
46211
|
+
if (b === false) return "off";
|
|
46212
|
+
return void 0;
|
|
46213
|
+
}
|
|
46214
|
+
function cachedMaintenanceMode(path) {
|
|
46215
|
+
try {
|
|
46216
|
+
if (!existsSync2(path)) return void 0;
|
|
46217
|
+
const parsed = JSON.parse(readFileSync4(path, "utf8"));
|
|
46218
|
+
if (!parsed || typeof parsed !== "object") return void 0;
|
|
46219
|
+
const flags = parsed.flags;
|
|
46220
|
+
if (!flags || typeof flags !== "object") return void 0;
|
|
46221
|
+
const value = flags[MAINTENANCE_FLAG_KEY];
|
|
46222
|
+
if (typeof value === "string") return parseMaintenanceMode(value);
|
|
46223
|
+
if (typeof value === "boolean") return value ? "fleet-offline" : "off";
|
|
46224
|
+
return void 0;
|
|
46225
|
+
} catch {
|
|
46226
|
+
return void 0;
|
|
46227
|
+
}
|
|
46228
|
+
}
|
|
46229
|
+
function resolveMaintenanceMode(opts) {
|
|
46230
|
+
const cached2 = cachedMaintenanceMode(opts?.cachePath ?? defaultFlagsCachePath());
|
|
46231
|
+
if (cached2 !== void 0) return cached2;
|
|
46232
|
+
return "off";
|
|
46233
|
+
}
|
|
46234
|
+
|
|
46235
|
+
// src/maintenance-tools-offline.ts
|
|
46236
|
+
function isToolsOfflineActive(opts) {
|
|
46237
|
+
const mode = resolveMaintenanceMode({ cachePath: opts?.cachePath, env: opts?.env });
|
|
46238
|
+
return mode === "tools-offline" || mode === "fleet-offline";
|
|
46239
|
+
}
|
|
46240
|
+
var MAINTENANCE_GATED_TOOLS = /* @__PURE__ */ new Set([
|
|
46241
|
+
// Tasks.
|
|
46242
|
+
"kanban_add",
|
|
46243
|
+
"kanban_update",
|
|
46244
|
+
"kanban_move",
|
|
46245
|
+
"kanban_done",
|
|
46246
|
+
"kanban_reopen",
|
|
46247
|
+
"kanban_assign",
|
|
46248
|
+
"kanban_reassign",
|
|
46249
|
+
"kanban_recall",
|
|
46250
|
+
"kanban_respond",
|
|
46251
|
+
"kanban_progress",
|
|
46252
|
+
"kanban_log",
|
|
46253
|
+
"kanban_assign_project",
|
|
46254
|
+
"assign_kanban_to_human",
|
|
46255
|
+
// Canvases. `dashboards_request_refresh` is gated because it enqueues
|
|
46256
|
+
// server-side work, not because it renders anything itself.
|
|
46257
|
+
"dashboards_upsert",
|
|
46258
|
+
"dashboards_persist_widget",
|
|
46259
|
+
"dashboards_request_refresh",
|
|
46260
|
+
// ───────────────────────────────────────────────────────────────────────
|
|
46261
|
+
// FORWARDED writes (ENG-11436 / CodeRabbit on #6903). These reach the agent
|
|
46262
|
+
// through `registerForwardedApiTools()` -> `server.registerTool`, from
|
|
46263
|
+
// `packages/api/src/routes/mcp-tools.ts`, with names resolved at RUNTIME. They
|
|
46264
|
+
// are gated only because index.ts now wraps that method too; before that, this
|
|
46265
|
+
// whole block would have been a list the gate could not see.
|
|
46266
|
+
//
|
|
46267
|
+
// CodeRabbit named five (workflow_update, workflow_run_{start,phase,end},
|
|
46268
|
+
// memory_delete). Enumerating the surface to check them found 37 of the 50
|
|
46269
|
+
// forwarded tools unclassified, so the five were a subset — these are all of
|
|
46270
|
+
// the writes among them. The test now classifies that surface exhaustively, so
|
|
46271
|
+
// the next addition fails CI rather than slipping through.
|
|
46272
|
+
"composio_upload_file",
|
|
46273
|
+
"memory_delete",
|
|
46274
|
+
"memory_save",
|
|
46275
|
+
"onboarding_advance",
|
|
46276
|
+
"onboarding_provision_skills",
|
|
46277
|
+
"onboarding_provision_tasks",
|
|
46278
|
+
"onboarding_record_manager_contact",
|
|
46279
|
+
"request_batch_approval",
|
|
46280
|
+
"request_integration_access",
|
|
46281
|
+
"skill_contribute_fragment",
|
|
46282
|
+
"skill_create",
|
|
46283
|
+
"skill_delete",
|
|
46284
|
+
"skill_improve",
|
|
46285
|
+
"skill_propose_revision",
|
|
46286
|
+
"skill_publish_to_marketplace",
|
|
46287
|
+
"skill_update",
|
|
46288
|
+
"submit_performance_review",
|
|
46289
|
+
"workflow_run_end",
|
|
46290
|
+
"workflow_run_phase",
|
|
46291
|
+
"workflow_run_start",
|
|
46292
|
+
"workflow_update",
|
|
46293
|
+
// CHANNEL-SERVER write (Obi Wan `b3537c1e8495` on #6903). Dispatched by NAME in
|
|
46294
|
+
// slack-channel.ts / telegram-channel.ts / direct-chat-channel.ts, which are
|
|
46295
|
+
// separate processes that never call server.tool — so this one is enforced by
|
|
46296
|
+
// `refuseIfToolsOffline` at each dispatch point, not by the registration
|
|
46297
|
+
// wrapper. It inserts a `pending_interaction` row, the same durable
|
|
46298
|
+
// human-actionable record that gates request_buttons / request_form.
|
|
46299
|
+
"channel_request_input",
|
|
46300
|
+
// `slack.ask_user` is the SAME write under a dotted name, and it was missed
|
|
46301
|
+
// because the test's enumerator could not see dotted names at all (Obi Wan
|
|
46302
|
+
// `122ac55ff278` / `d7245eddd77f` on #6903). handleAskUser calls
|
|
46303
|
+
// runtime.createPendingInteraction -> POST /host/pending-interactions ->
|
|
46304
|
+
// inserts `pending_interaction`. Ungated, an agent on a /loop files the row,
|
|
46305
|
+
// the restore discards it, and the agent blocks forever on a resolution that
|
|
46306
|
+
// no longer exists — the exact failure the entry above is gated for.
|
|
46307
|
+
//
|
|
46308
|
+
// Verified it is the ONLY dotted channel tool that writes: createPendingInteraction
|
|
46309
|
+
// is CALLED once in the three channel servers (slack-channel.ts:8053);
|
|
46310
|
+
// slack-block-kit-runtime.ts only re-exports it.
|
|
46311
|
+
"slack.ask_user",
|
|
46312
|
+
// Workflows. FORWARDED, not local — it reaches the agent through
|
|
46313
|
+
// `server.registerTool` in registerForwardedApiTools, so it is gated only
|
|
46314
|
+
// because that method is now wrapped too (CodeRabbit on #6903).
|
|
46315
|
+
"workflow_create",
|
|
46316
|
+
// Knowledge.
|
|
46317
|
+
"knowledge_add",
|
|
46318
|
+
"knowledge_update",
|
|
46319
|
+
"knowledge_delete",
|
|
46320
|
+
// Projects and project tagging.
|
|
46321
|
+
"projects_create",
|
|
46322
|
+
"projects_update",
|
|
46323
|
+
"artefacts_assign_project",
|
|
46324
|
+
// Routines.
|
|
46325
|
+
"routine_propose",
|
|
46326
|
+
"routine_revise",
|
|
46327
|
+
"routine_retire",
|
|
46328
|
+
"submit_routine_output",
|
|
46329
|
+
// Standing rules.
|
|
46330
|
+
"rule_add",
|
|
46331
|
+
"rule_remove",
|
|
46332
|
+
// Scheduled work.
|
|
46333
|
+
"schedule_create",
|
|
46334
|
+
"schedule_update",
|
|
46335
|
+
"schedule_delete",
|
|
46336
|
+
// Requests that file a durable record a human is expected to act on. Filing
|
|
46337
|
+
// one mid-window is worse than refusing it: the record is discarded by the
|
|
46338
|
+
// restore, so the agent would have promised a human a follow-up that no
|
|
46339
|
+
// longer exists anywhere.
|
|
46340
|
+
"request_approval",
|
|
46341
|
+
"request_buttons",
|
|
46342
|
+
"request_channel_access",
|
|
46343
|
+
"request_form",
|
|
46344
|
+
"request_reconnect",
|
|
46345
|
+
"request_feature",
|
|
46346
|
+
"request_feature_withdraw",
|
|
46347
|
+
// ADR-0025 approval tools, registered by `approval-tools.ts` against the same
|
|
46348
|
+
// server object, so the wrapper in index.ts covers them too.
|
|
46349
|
+
"cancel_approval",
|
|
46350
|
+
// Status / identity.
|
|
46351
|
+
"status_standup",
|
|
46352
|
+
"status_update",
|
|
46353
|
+
"update_identity",
|
|
46354
|
+
"update_timezone",
|
|
46355
|
+
// Fleet changes.
|
|
46356
|
+
"recruit_agent",
|
|
46357
|
+
"integration_improve"
|
|
46358
|
+
]);
|
|
46359
|
+
function toolsOfflineRefusalText(toolName) {
|
|
46360
|
+
return `Ninjafy is in a control-plane maintenance window, so \`${toolName}\` is unavailable right now. Nothing was created, changed or saved. Do NOT retry this call, and do not try a different Ninjafy tool to work around it \u2014 every tool that writes to the control plane is refusing for the same reason, and the window is short. Tell the person plainly that you cannot save this at the moment and ask them to bring it back afterwards; carry on with anything that does not need saving.`;
|
|
46361
|
+
}
|
|
46362
|
+
function withMaintenanceGate(name, handler, opts) {
|
|
46363
|
+
if (!MAINTENANCE_GATED_TOOLS.has(name)) return handler;
|
|
46364
|
+
const isActive = opts?.isActive ?? (() => isToolsOfflineActive());
|
|
46365
|
+
const gated = async (...args) => {
|
|
46366
|
+
if (isActive()) {
|
|
46367
|
+
return { content: [{ type: "text", text: toolsOfflineRefusalText(name) }] };
|
|
46368
|
+
}
|
|
46369
|
+
return handler(...args);
|
|
46370
|
+
};
|
|
46371
|
+
return gated;
|
|
46372
|
+
}
|
|
46373
|
+
|
|
46092
46374
|
// src/json-schema-to-zod-shape.ts
|
|
46093
46375
|
function jsonSchemaToZodShape(schema) {
|
|
46094
46376
|
if (!schema || schema["type"] !== "object") return {};
|
|
@@ -46838,12 +47120,12 @@ function selectIntegrationsToRefresh(input) {
|
|
|
46838
47120
|
}
|
|
46839
47121
|
|
|
46840
47122
|
// src/self-restart.ts
|
|
46841
|
-
import { existsSync as
|
|
46842
|
-
import { homedir as
|
|
46843
|
-
import { join as
|
|
47123
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
47124
|
+
import { homedir as homedir3 } from "os";
|
|
47125
|
+
import { join as join7 } from "path";
|
|
46844
47126
|
import { randomUUID } from "crypto";
|
|
46845
47127
|
function restartFlagsDir() {
|
|
46846
|
-
return
|
|
47128
|
+
return join7(homedir3(), ".augmented", "restart-flags");
|
|
46847
47129
|
}
|
|
46848
47130
|
function isSelfRestartEnabled(env2) {
|
|
46849
47131
|
const raw = (env2.AGT_AGENT_SELF_RESTART_ENABLED ?? "").trim().toLowerCase();
|
|
@@ -46854,8 +47136,8 @@ function buildAgentRestartFlag(codeName, reason, nowMs) {
|
|
|
46854
47136
|
}
|
|
46855
47137
|
function writeAgentRestartFlag(codeName, reason, nowMs) {
|
|
46856
47138
|
const dir = restartFlagsDir();
|
|
46857
|
-
if (!
|
|
46858
|
-
const path =
|
|
47139
|
+
if (!existsSync3(dir)) mkdirSync3(dir, { recursive: true });
|
|
47140
|
+
const path = join7(dir, `${codeName}.flag`);
|
|
46859
47141
|
const flag = buildAgentRestartFlag(codeName, reason, nowMs);
|
|
46860
47142
|
const tmpPath = `${path}.${process.pid}.${randomUUID()}.tmp`;
|
|
46861
47143
|
writeFileSync2(tmpPath, JSON.stringify(flag) + "\n", "utf8");
|
|
@@ -46864,18 +47146,18 @@ function writeAgentRestartFlag(codeName, reason, nowMs) {
|
|
|
46864
47146
|
}
|
|
46865
47147
|
|
|
46866
47148
|
// src/self-restart-confirm.ts
|
|
46867
|
-
import { existsSync as
|
|
46868
|
-
import { homedir as
|
|
46869
|
-
import { join as
|
|
47149
|
+
import { existsSync as existsSync5, readdirSync, readFileSync as readFileSync6 } from "fs";
|
|
47150
|
+
import { homedir as homedir4 } from "os";
|
|
47151
|
+
import { join as join8 } from "path";
|
|
46870
47152
|
|
|
46871
47153
|
// src/restart-confirm.ts
|
|
46872
|
-
import { existsSync as
|
|
47154
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync5, renameSync as renameSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
46873
47155
|
import { dirname as dirname4 } from "path";
|
|
46874
47156
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
46875
47157
|
var RESTART_CONFIRM_MAX_AGE_MS = 10 * 60 * 1e3;
|
|
46876
47158
|
function writeRestartConfirmMarker(filePath, marker) {
|
|
46877
47159
|
const dir = dirname4(filePath);
|
|
46878
|
-
if (!
|
|
47160
|
+
if (!existsSync4(dir)) mkdirSync4(dir, { recursive: true, mode: 448 });
|
|
46879
47161
|
const tmpPath = `${filePath}.${process.pid}.${randomUUID2()}.tmp`;
|
|
46880
47162
|
writeFileSync3(tmpPath, JSON.stringify(marker) + "\n", { encoding: "utf8", mode: 384 });
|
|
46881
47163
|
renameSync3(tmpPath, filePath);
|
|
@@ -46884,7 +47166,7 @@ function writeRestartConfirmMarker(filePath, marker) {
|
|
|
46884
47166
|
// src/self-restart-confirm.ts
|
|
46885
47167
|
var SELF_RESTART_PENDING_FRESHNESS_MS = 5 * 60 * 1e3;
|
|
46886
47168
|
function selfRestartAgentDir(codeName) {
|
|
46887
|
-
return
|
|
47169
|
+
return join8(homedir4(), ".augmented", codeName);
|
|
46888
47170
|
}
|
|
46889
47171
|
function selectFreshestPending(candidates, nowMs, maxAgeMs) {
|
|
46890
47172
|
let best = null;
|
|
@@ -46897,7 +47179,7 @@ function selectFreshestPending(candidates, nowMs, maxAgeMs) {
|
|
|
46897
47179
|
return best;
|
|
46898
47180
|
}
|
|
46899
47181
|
function readMarkerDir(dir, toCandidate) {
|
|
46900
|
-
if (!
|
|
47182
|
+
if (!existsSync5(dir)) return [];
|
|
46901
47183
|
const out = [];
|
|
46902
47184
|
let entries;
|
|
46903
47185
|
try {
|
|
@@ -46908,7 +47190,7 @@ function readMarkerDir(dir, toCandidate) {
|
|
|
46908
47190
|
for (const entry of entries) {
|
|
46909
47191
|
if (!entry.endsWith(".json") || entry.endsWith(".tmp")) continue;
|
|
46910
47192
|
try {
|
|
46911
|
-
const parsed = JSON.parse(
|
|
47193
|
+
const parsed = JSON.parse(readFileSync6(join8(dir, entry), "utf8"));
|
|
46912
47194
|
if (!parsed || typeof parsed !== "object") continue;
|
|
46913
47195
|
const candidate = toCandidate(parsed);
|
|
46914
47196
|
if (candidate) out.push(candidate);
|
|
@@ -46918,7 +47200,7 @@ function readMarkerDir(dir, toCandidate) {
|
|
|
46918
47200
|
return out;
|
|
46919
47201
|
}
|
|
46920
47202
|
function readPendingCandidates(agentDir) {
|
|
46921
|
-
const slack = readMarkerDir(
|
|
47203
|
+
const slack = readMarkerDir(join8(agentDir, "slack-pending-inbound"), (p2) => {
|
|
46922
47204
|
const channel = p2["channel"];
|
|
46923
47205
|
if (typeof channel !== "string" || channel.length === 0) return null;
|
|
46924
47206
|
const threadTs = p2["thread_ts"];
|
|
@@ -46926,7 +47208,7 @@ function readPendingCandidates(agentDir) {
|
|
|
46926
47208
|
if (typeof threadTs === "string" && threadTs.length > 0) reply["thread_ts"] = threadTs;
|
|
46927
47209
|
return { source: "slack", receivedAtMs: Date.parse(String(p2["received_at"])), reply };
|
|
46928
47210
|
});
|
|
46929
|
-
const telegram = readMarkerDir(
|
|
47211
|
+
const telegram = readMarkerDir(join8(agentDir, "telegram-pending-inbound"), (p2) => {
|
|
46930
47212
|
const chatId = p2["chat_id"];
|
|
46931
47213
|
if (chatId == null || typeof chatId !== "string" && typeof chatId !== "number") return null;
|
|
46932
47214
|
const reply = { chat_id: chatId };
|
|
@@ -46947,17 +47229,17 @@ function captureSelfRestartConfirm(opts) {
|
|
|
46947
47229
|
// human, so buildBackOnlineText degrades to the generic copy.
|
|
46948
47230
|
reply: best.reply
|
|
46949
47231
|
};
|
|
46950
|
-
const file = best.source === "slack" ?
|
|
47232
|
+
const file = best.source === "slack" ? join8(opts.agentDir, "slack-restart-confirm.json") : join8(opts.agentDir, "telegram-restart-confirm.json");
|
|
46951
47233
|
writeRestartConfirmMarker(file, marker);
|
|
46952
47234
|
return best.source;
|
|
46953
47235
|
}
|
|
46954
47236
|
|
|
46955
47237
|
// ../core/dist/integrations/forwarded-tools-report.js
|
|
46956
|
-
import { readFileSync as
|
|
46957
|
-
import { join as
|
|
47238
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
47239
|
+
import { join as join9 } from "path";
|
|
46958
47240
|
var FORWARDED_TOOLS_REPORT_FILENAME = "forwarded-tools.json";
|
|
46959
47241
|
function forwardedToolsReportPath(agentDir) {
|
|
46960
|
-
return
|
|
47242
|
+
return join9(agentDir, FORWARDED_TOOLS_REPORT_FILENAME);
|
|
46961
47243
|
}
|
|
46962
47244
|
function writeForwardedToolsReport(agentDir, report) {
|
|
46963
47245
|
try {
|
|
@@ -47972,6 +48254,26 @@ var server = new McpServer({
|
|
|
47972
48254
|
name: "augmented",
|
|
47973
48255
|
version: "0.1.0"
|
|
47974
48256
|
});
|
|
48257
|
+
var wrapRegistration = (original) => (...args) => {
|
|
48258
|
+
const name = args[0];
|
|
48259
|
+
const handlerIndex = args.length - 1;
|
|
48260
|
+
const handler = args[handlerIndex];
|
|
48261
|
+
if (typeof name === "string" && typeof handler === "function") {
|
|
48262
|
+
const rewritten = [...args];
|
|
48263
|
+
rewritten[handlerIndex] = withMaintenanceGate(
|
|
48264
|
+
name,
|
|
48265
|
+
handler
|
|
48266
|
+
);
|
|
48267
|
+
return original(...rewritten);
|
|
48268
|
+
}
|
|
48269
|
+
return original(...args);
|
|
48270
|
+
};
|
|
48271
|
+
var registerToolUnwrapped = server.tool.bind(server);
|
|
48272
|
+
server.tool = wrapRegistration(registerToolUnwrapped);
|
|
48273
|
+
var registerToolV2Unwrapped = server.registerTool.bind(server);
|
|
48274
|
+
server.registerTool = wrapRegistration(
|
|
48275
|
+
registerToolV2Unwrapped
|
|
48276
|
+
);
|
|
47975
48277
|
if (AGT_AGENT_ID) {
|
|
47976
48278
|
registerApprovalTools(server, { agentId: AGT_AGENT_ID, apiPost, apiGet });
|
|
47977
48279
|
}
|
|
@@ -50906,9 +51208,9 @@ async function forwardToolCall(toolName, args) {
|
|
|
50906
51208
|
// root to its canonical form so both sides of the comparison are real
|
|
50907
51209
|
// paths. Falls back to the unresolved join if the dir is missing, which
|
|
50908
51210
|
// then simply refuses (there is nothing to read anyway).
|
|
50909
|
-
agentDir: canonicalAgentDir(
|
|
51211
|
+
agentDir: canonicalAgentDir(join10(homedir5(), ".augmented", AGT_AGENT_CODE_NAME)),
|
|
50910
51212
|
// agent-dir-allow: immediately realpath-resolved to the ADR-0049 agent_id-keyed dir before use as a containment root
|
|
50911
|
-
path: { isAbsolute: isAbsolute2, resolve: pathResolve, join:
|
|
51213
|
+
path: { isAbsolute: isAbsolute2, resolve: pathResolve, join: join10, sep: sep2 },
|
|
50912
51214
|
// O_NOFOLLOW is the whole point of opening by flags: the path is already
|
|
50913
51215
|
// symlink-resolved, so a symlink at the final component means it was
|
|
50914
51216
|
// swapped after the check, and this turns that into an ELOOP.
|
|
@@ -51331,7 +51633,7 @@ async function saveArtefactSourceToFile(artefactId) {
|
|
|
51331
51633
|
codeName: AGT_AGENT_CODE_NAME,
|
|
51332
51634
|
turnInitiatorFile: process.env.AGT_TURN_INITIATOR_FILE,
|
|
51333
51635
|
agentId: AGT_AGENT_ID,
|
|
51334
|
-
homeDir:
|
|
51636
|
+
homeDir: homedir5()
|
|
51335
51637
|
});
|
|
51336
51638
|
const readOnce = async () => {
|
|
51337
51639
|
const before = await fetchArtefactRevision(artefactId);
|
|
@@ -51346,7 +51648,7 @@ async function saveArtefactSourceToFile(artefactId) {
|
|
|
51346
51648
|
};
|
|
51347
51649
|
let result = await readOnce();
|
|
51348
51650
|
if (result.revisionState !== "stable") result = await readOnce();
|
|
51349
|
-
const filePath =
|
|
51651
|
+
const filePath = join10(dir, safeDownloadName(`${artefactId}.html`, `${artefactId}.html`));
|
|
51350
51652
|
await writeFile(filePath, result.html, "utf8");
|
|
51351
51653
|
return {
|
|
51352
51654
|
path: filePath,
|
|
@@ -51427,7 +51729,7 @@ async function exportArtefactToFile(dir, artefactId, format, item) {
|
|
|
51427
51729
|
return { kind: "pending", jobId: outcome.jobId, retryAfterMs: outcome.retryAfterMs };
|
|
51428
51730
|
}
|
|
51429
51731
|
const fallback = `${artefactId}${item !== void 0 ? `-item-${item + 1}` : ""}.${format}`;
|
|
51430
|
-
const filePath =
|
|
51732
|
+
const filePath = join10(dir, safeDownloadName(outcome.body.filename, fallback));
|
|
51431
51733
|
const buf = Buffer.from(outcome.body.base64, "base64");
|
|
51432
51734
|
await writeFile(filePath, buf);
|
|
51433
51735
|
return {
|
|
@@ -51454,7 +51756,7 @@ async function downloadArtefactText(params) {
|
|
|
51454
51756
|
codeName: AGT_AGENT_CODE_NAME,
|
|
51455
51757
|
turnInitiatorFile: process.env.AGT_TURN_INITIATOR_FILE,
|
|
51456
51758
|
agentId: AGT_AGENT_ID,
|
|
51457
|
-
homeDir:
|
|
51759
|
+
homeDir: homedir5()
|
|
51458
51760
|
});
|
|
51459
51761
|
let items;
|
|
51460
51762
|
let truncatedFrom = null;
|