@integrity-labs/agt-cli 0.27.9-test.12 → 0.27.9-test.14
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 +4 -4
- package/dist/chunk-354FAVQR.js +173 -0
- package/dist/chunk-354FAVQR.js.map +1 -0
- package/dist/{chunk-MQJ5DMPT.js → chunk-7GKJZBTB.js} +111 -204
- package/dist/chunk-7GKJZBTB.js.map +1 -0
- package/dist/{chunk-HR5T2RQF.js → chunk-I3YS5WFV.js} +3 -1
- package/dist/chunk-I3YS5WFV.js.map +1 -0
- package/dist/{chunk-SXBZDUKN.js → chunk-R7NKCGWN.js} +341 -46
- package/dist/chunk-R7NKCGWN.js.map +1 -0
- package/dist/{chunk-I2OTQJH3.js → chunk-WOOYOAPG.js} +2644 -2142
- package/dist/chunk-WOOYOAPG.js.map +1 -0
- package/dist/{claude-pair-runtime-F6USL3EW.js → claude-pair-runtime-GIUCD7IG.js} +2 -2
- package/dist/{claude-scheduler-EM24LTGV.js → claude-scheduler-FATCLHDM.js} +2 -2
- package/dist/daily-session-PNQX5URX.js +27 -0
- package/dist/lib/manager-worker.js +1125 -149
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/augmented-admin.js +21335 -0
- package/dist/mcp/index.js +121 -4
- package/dist/mcp/slack-channel.js +845 -208
- package/dist/mcp/teams-channel.js +73 -29
- package/dist/mcp/telegram-channel.js +579 -157
- package/dist/{persistent-session-OL5EDYB4.js → persistent-session-35PWSTLO.js} +10 -3
- package/dist/persistent-session-35PWSTLO.js.map +1 -0
- package/dist/responsiveness-probe-MA4M2QM4.js +158 -0
- package/dist/responsiveness-probe-MA4M2QM4.js.map +1 -0
- package/package.json +3 -2
- package/dist/chunk-HR5T2RQF.js.map +0 -1
- package/dist/chunk-I2OTQJH3.js.map +0 -1
- package/dist/chunk-MQJ5DMPT.js.map +0 -1
- package/dist/chunk-SXBZDUKN.js.map +0 -1
- package/dist/responsiveness-probe-B6LJJRUD.js +0 -74
- package/dist/responsiveness-probe-B6LJJRUD.js.map +0 -1
- /package/dist/{claude-pair-runtime-F6USL3EW.js.map → claude-pair-runtime-GIUCD7IG.js.map} +0 -0
- /package/dist/{claude-scheduler-EM24LTGV.js.map → claude-scheduler-FATCLHDM.js.map} +0 -0
- /package/dist/{persistent-session-OL5EDYB4.js.map → daily-session-PNQX5URX.js.map} +0 -0
|
@@ -8,8 +8,9 @@ import {
|
|
|
8
8
|
isParseError,
|
|
9
9
|
parseDeliveryTarget,
|
|
10
10
|
registerFramework,
|
|
11
|
+
resolveAvatarEnvUrl,
|
|
11
12
|
wrapScheduledTaskPrompt
|
|
12
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-WOOYOAPG.js";
|
|
13
14
|
|
|
14
15
|
// ../../packages/core/dist/integrations/registry.js
|
|
15
16
|
var INTEGRATION_REGISTRY = [
|
|
@@ -49,7 +50,13 @@ var INTEGRATION_REGISTRY = [
|
|
|
49
50
|
binary: "gh",
|
|
50
51
|
env_key: "GITHUB_TOKEN",
|
|
51
52
|
skill_id: "gh-cli",
|
|
52
|
-
|
|
53
|
+
// ENG-6206: `brew` never installs on the Linux fleet (root-on-AL2023,
|
|
54
|
+
// no Homebrew) — gh was permanently missing. Use an OS-detecting script
|
|
55
|
+
// that installs from GitHub's official repos: dnf (AL2023 / RHEL),
|
|
56
|
+
// apt (Debian / Ubuntu), and brew (macOS hosts). The catalog is the
|
|
57
|
+
// trust boundary — this string is source-controlled, never runtime data.
|
|
58
|
+
installer: "script",
|
|
59
|
+
script: 'if command -v dnf >/dev/null 2>&1; then curl -fsSL https://cli.github.com/packages/rpm/gh-cli.repo -o /etc/yum.repos.d/gh-cli.repo && dnf install -y gh; elif command -v apt-get >/dev/null 2>&1; then curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg -o /usr/share/keyrings/githubcli-archive-keyring.gpg && chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list && apt-get update && apt-get install -y gh; elif command -v brew >/dev/null 2>&1; then brew install gh; else echo "gh: no supported installer (need dnf, apt-get, or brew)" >&2; exit 1; fi'
|
|
53
60
|
}
|
|
54
61
|
},
|
|
55
62
|
{
|
|
@@ -381,6 +388,24 @@ var INTEGRATION_REGISTRY = [
|
|
|
381
388
|
}
|
|
382
389
|
}
|
|
383
390
|
},
|
|
391
|
+
{
|
|
392
|
+
// ENG-6195: admin-only debugging surface for Integrity Labs STAFF agents.
|
|
393
|
+
// Provisions the @integrity-labs/augmented-admin-mcp stdio broker, which
|
|
394
|
+
// reads end-user agent diagnostics cross-org via /admin/debug/*. `beta` so
|
|
395
|
+
// it is visible/enable-able only by admin-email-domain users; the API
|
|
396
|
+
// double-gates every call on the caller's owning org `is_internal = true`.
|
|
397
|
+
// auth `none` — no end-user OAuth; the host JWT (org_id claim) is the
|
|
398
|
+
// credential. NOT a customer integration; do not promote to `published`.
|
|
399
|
+
id: "augmented-admin",
|
|
400
|
+
name: "Augmented Admin Debug",
|
|
401
|
+
category: "infrastructure",
|
|
402
|
+
description: "Integrity Labs staff-only: cross-org agent/host/integration/alert diagnostics for troubleshooting managed agents.",
|
|
403
|
+
supported_auth_types: ["none"],
|
|
404
|
+
beta: true,
|
|
405
|
+
capabilities: [
|
|
406
|
+
{ id: "augmented-admin:read-diagnostics", name: "Read Diagnostics", description: "Cross-org read of agent, host, integration, and alert diagnostics (projection only \u2014 never credentials or transcripts).", access: "read" }
|
|
407
|
+
]
|
|
408
|
+
},
|
|
384
409
|
{
|
|
385
410
|
id: "custom",
|
|
386
411
|
name: "Custom Integration",
|
|
@@ -3361,32 +3386,43 @@ acknowledge before you start.
|
|
|
3361
3386
|
- **FAST (< 60s):** handle inline. Reply via the channel tool
|
|
3362
3387
|
(slack.reply / telegram.reply / directchat.reply) and end your turn.
|
|
3363
3388
|
|
|
3364
|
-
- **SLOW (\u2265 60s):** acknowledge
|
|
3389
|
+
- **SLOW (\u2265 60s):** acknowledge, dispatch to background, stay responsive.
|
|
3365
3390
|
1. Send a one-line acknowledgement via the channel tool \u2014 short, warm,
|
|
3366
3391
|
and tell the user you'll come back. Example shape (don't copy verbatim,
|
|
3367
3392
|
match your voice): "On it \u2014 this'll take a minute or two, I'll ping
|
|
3368
3393
|
when it's done."
|
|
3369
|
-
2.
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
>
|
|
3389
|
-
>
|
|
3394
|
+
2. Dispatch the work to a background sub-agent: the Agent tool with
|
|
3395
|
+
\`subagent_type: general-purpose\` AND \`run_in_background: true\`.
|
|
3396
|
+
Put EVERYTHING the worker needs in the dispatch prompt \u2014 the user's
|
|
3397
|
+
full request, relevant thread context, which integrations/tools to
|
|
3398
|
+
use, and the exact shape of result you want back. The worker inherits
|
|
3399
|
+
your full MCP tool surface but NOT your conversation context.
|
|
3400
|
+
3. End your turn after dispatching. This is the point: you stay free to
|
|
3401
|
+
answer other messages while the worker grinds. Do NOT wait, poll, or
|
|
3402
|
+
dispatch the same work synchronously \u2014 a synchronous dispatch blocks
|
|
3403
|
+
your turn and defeats the purpose.
|
|
3404
|
+
4. When the worker's completion notification arrives (it lands
|
|
3405
|
+
automatically as a system message), read its result and reply via the
|
|
3406
|
+
channel tool (\`slack.reply\` / \`telegram.reply\` / \`directchat.reply\`)
|
|
3407
|
+
to the same thread / chat / conversation you acknowledged in step 1.
|
|
3408
|
+
**You post the substantive reply \u2014 the worker has no channel tools.**
|
|
3409
|
+
5. If the completion notification reports a failure or an unusable
|
|
3410
|
+
result, tell the user what happened and either re-dispatch with a
|
|
3411
|
+
better prompt or handle it inline \u2014 never go silent.
|
|
3412
|
+
|
|
3413
|
+
> **Why background dispatch (and why \`general-purpose\`):** validated
|
|
3414
|
+
> 2026-06-10 on Claude Code 2.1.170 (ENG-6274 spike,
|
|
3415
|
+
> \`docs/spikes/ENG-6274-run-in-background-dispatch.md\`): background
|
|
3416
|
+
> dispatch returns immediately, your turn ends, inbound messages get
|
|
3417
|
+
> answered in seconds while the worker runs, and the completion arrives
|
|
3418
|
+
> as a notification you handle like any other turn. Use
|
|
3419
|
+
> \`subagent_type: general-purpose\` (inherit-all tools) \u2014 NOT
|
|
3420
|
+
> \`channel-message-handler\` or \`augmented-worker\` \u2014 until ENG-6273
|
|
3421
|
+
> re-verifies on this host that the upstream allowlist bug
|
|
3422
|
+
> ([anthropics/claude-code#64909](https://github.com/anthropics/claude-code/issues/64909),
|
|
3423
|
+
> empirically 0/6 MCP tools in named sub-agents on 2026-06-03) is fixed
|
|
3424
|
+
> at the fleet's pinned Claude Code version. \`general-purpose\` escapes
|
|
3425
|
+
> that bug by construction either way.
|
|
3390
3426
|
|
|
3391
3427
|
**Why this triage decision still matters more than any other instruction
|
|
3392
3428
|
below:** if you skip the acknowledgement and just dive into slow work
|
|
@@ -3408,25 +3444,29 @@ For background tool work that **isn't** a channel reply \u2014 multi-step data
|
|
|
3408
3444
|
pulls, CRM enrichments, research workflows, cross-MCP orchestration \u2014 use
|
|
3409
3445
|
\`subagent_type: general-purpose\` (Anthropic's built-in). It inherits the
|
|
3410
3446
|
full MCP tool surface from this session and reliably binds every
|
|
3411
|
-
\`mcp__*\` server you have available.
|
|
3447
|
+
\`mcp__*\` server you have available. For anything expected to take more
|
|
3448
|
+
than a minute, add \`run_in_background: true\` so your turn ends and you
|
|
3449
|
+
stay responsive; the completion notification brings you the result.
|
|
3450
|
+
Don't background-dispatch trivial work \u2014 each dispatch is a fresh
|
|
3451
|
+
context and costs real tokens.
|
|
3412
3452
|
|
|
3413
3453
|
**Why not \`augmented-worker\` for now:** there is an upstream Claude Code
|
|
3414
3454
|
bug ([anthropics/claude-code#64909](https://github.com/anthropics/claude-code/issues/64909))
|
|
3415
3455
|
where sub-agents with an explicit \`tools:\` allowlist get an empty MCP
|
|
3416
3456
|
tool registry \u2014 every \`mcp__*\` call returns "No such tool available."
|
|
3417
3457
|
\`general-purpose\` uses \`tools: *\` (inherit-all) and escapes the bug.
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3458
|
+
The fix appears to have shipped upstream (verified locally on Claude Code
|
|
3459
|
+
2.1.170, 2026-06-10 \u2014 ENG-6269 spike); once ENG-6273 re-verifies it on
|
|
3460
|
+
this host's pinned version, \`augmented-worker\` becomes preferred again
|
|
3461
|
+
(restricted tool surface for safety + working MCP binding) and
|
|
3462
|
+
\`channel-message-handler\` returns as a dispatch target. Until then,
|
|
3463
|
+
\`general-purpose\` only.
|
|
3421
3464
|
|
|
3422
3465
|
For slow **channel** replies, see \xA7 FIRST ACTION above \u2014 those are
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
\`augmented-worker\` result). When Anthropic ships the upstream fix, both
|
|
3428
|
-
named sub-agents will work again and the FIRST ACTION triage will switch
|
|
3429
|
-
back to dispatch.
|
|
3466
|
+
dispatched as background \`general-purpose\` workers and **you** post the
|
|
3467
|
+
result back to the channel when the completion notification arrives
|
|
3468
|
+
(\`channel-message-handler\` is not yet the dispatch target for the same
|
|
3469
|
+
ENG-6273-pending reason).
|
|
3430
3470
|
|
|
3431
3471
|
${activeTasksSection}${personalitySection}## Identity
|
|
3432
3472
|
|
|
@@ -3635,8 +3675,15 @@ ask the question alone, no task created yet, and let the user answer before
|
|
|
3635
3675
|
anything goes on the board.
|
|
3636
3676
|
|
|
3637
3677
|
When asked about existing work, tasks, or what you've been doing \u2014 call kanban.list
|
|
3638
|
-
first to load your recent board state
|
|
3639
|
-
|
|
3678
|
+
first to load your recent board state (active items + the last 24h of completed work).
|
|
3679
|
+
|
|
3680
|
+
**But kanban.list is recency-windowed: done cards older than 24h are NOT on it** (only done cards age off \u2014 failed and active cards always show).
|
|
3681
|
+
So if someone references specific past work ("you drafted X for me", "did you finish Y
|
|
3682
|
+
on the weekend?"), do NOT answer from the board alone \u2014 run **kanban.search** for it
|
|
3683
|
+
first. "It's not on my board" only means it's older than 24h, not that you never did it.
|
|
3684
|
+
Each search hit includes the card's result, so you can recite what you actually
|
|
3685
|
+
produced. Denying delivered work because it aged off the board is a serious failure of
|
|
3686
|
+
trust \u2014 search before you say "no record".
|
|
3640
3687
|
|
|
3641
3688
|
${memorySection}
|
|
3642
3689
|
${reportsToSection}${teamSection}${peopleSection}${multiAgentSection}${integrationsSection}${capabilityPromptSection}${knowledgeSection}${kanbanWorkPolicySection}${skillAuthoringSection}## Dashboards
|
|
@@ -4633,6 +4680,136 @@ function provisionIsolationHook(codeName) {
|
|
|
4633
4680
|
settings["hooks"] = hooks;
|
|
4634
4681
|
writeFileSync5(settingsPath, JSON.stringify(settings, null, 2));
|
|
4635
4682
|
}
|
|
4683
|
+
function provisionAutoKanbanProgressHook(codeName) {
|
|
4684
|
+
const projectDir = getProjectDir(codeName);
|
|
4685
|
+
const claudeDir = join4(projectDir, ".claude");
|
|
4686
|
+
mkdirSync4(claudeDir, { recursive: true });
|
|
4687
|
+
const hookScriptPath = join4(claudeDir, "agt-auto-kanban-progress-hook.sh");
|
|
4688
|
+
const hookScript = `#!/usr/bin/env bash
|
|
4689
|
+
# Auto-generated by Augmented (ENG-6179 / ENG-6241) \u2014 PostToolUse auto-progress.
|
|
4690
|
+
# Maps the agent's latest tool action onto its active in-thread kanban progress
|
|
4691
|
+
# card. Best-effort, silent, throttled; every path degrades to exit 0 and the
|
|
4692
|
+
# push is fire-and-forget so it never blocks or fails a tool call.
|
|
4693
|
+
# Canonical source: packages/claudecode-plugin-augmented/hooks/auto-kanban-progress.sh
|
|
4694
|
+
|
|
4695
|
+
# Best-effort: any unexpected error just exits clean.
|
|
4696
|
+
trap 'exit 0' ERR
|
|
4697
|
+
|
|
4698
|
+
# Hook input (stdin canonical; CLAUDE_HOOK_INPUT kept as a fallback).
|
|
4699
|
+
INPUT="$(cat 2>/dev/null || true)"
|
|
4700
|
+
[ -n "$INPUT" ] || INPUT="\${CLAUDE_HOOK_INPUT:-}"
|
|
4701
|
+
[ -n "$INPUT" ] || exit 0
|
|
4702
|
+
command -v jq >/dev/null 2>&1 || exit 0
|
|
4703
|
+
command -v curl >/dev/null 2>&1 || exit 0
|
|
4704
|
+
|
|
4705
|
+
TOOL="$(printf '%s' "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null || true)"
|
|
4706
|
+
[ -n "$TOOL" ] || exit 0
|
|
4707
|
+
|
|
4708
|
+
# Skip tools that aren't "work the requester wants narrated". kanban_* (incl.
|
|
4709
|
+
# the explicit kanban_progress) and channel/status tools would only produce
|
|
4710
|
+
# noise \u2014 and a kanban_done clears the step anyway.
|
|
4711
|
+
case "$TOOL" in
|
|
4712
|
+
*kanban*|*reply*|*ask_user*|*send_message*|*direct_chat*|status_*|TodoWrite|ExitPlanMode) exit 0 ;;
|
|
4713
|
+
esac
|
|
4714
|
+
|
|
4715
|
+
# Identity + endpoint.
|
|
4716
|
+
PROJECT_DIR="\${CLAUDE_PROJECT_DIR:-$PWD}"
|
|
4717
|
+
AGENT_ID="\${AGT_AGENT_ID:-}"
|
|
4718
|
+
if [ -z "$AGENT_ID" ] && [ -f "$PROJECT_DIR/.mcp.json" ]; then
|
|
4719
|
+
# The manager writes AGT_AGENT_ID literally into every augmented MCP server's
|
|
4720
|
+
# env block; take the first non-empty one.
|
|
4721
|
+
AGENT_ID="$(jq -r '[.mcpServers[]?.env?.AGT_AGENT_ID // empty] | map(select(. != "")) | .[0] // empty' "$PROJECT_DIR/.mcp.json" 2>/dev/null || true)"
|
|
4722
|
+
fi
|
|
4723
|
+
HOST="\${AGT_HOST:-}"
|
|
4724
|
+
KEY="\${AGT_API_KEY:-}"
|
|
4725
|
+
[ -n "$AGENT_ID" ] && [ -n "$HOST" ] && [ -n "$KEY" ] || exit 0
|
|
4726
|
+
|
|
4727
|
+
# Throttle: at most one push per ~15s per agent.
|
|
4728
|
+
STATE_DIR="\${HOME:-/tmp}/.augmented/.auto-progress/\${AGENT_ID}"
|
|
4729
|
+
mkdir -p "$STATE_DIR" 2>/dev/null || exit 0
|
|
4730
|
+
STAMP="$STATE_DIR/last-push"
|
|
4731
|
+
NOW="$(date +%s)"
|
|
4732
|
+
if [ -f "$STAMP" ]; then
|
|
4733
|
+
LAST="$(cat "$STAMP" 2>/dev/null || echo 0)"
|
|
4734
|
+
case "$LAST" in ''|*[!0-9]*) LAST=0 ;; esac
|
|
4735
|
+
[ $(( NOW - LAST )) -ge 15 ] || exit 0
|
|
4736
|
+
fi
|
|
4737
|
+
|
|
4738
|
+
# Derive the one-line "what I'm doing right now" step.
|
|
4739
|
+
STEP="$(printf '%s' "$INPUT" | jq -r '
|
|
4740
|
+
def base(p): (p | tostring | ltrimstr("./") | split("/") | last);
|
|
4741
|
+
.tool_name as $t | (.tool_input // {}) as $i |
|
|
4742
|
+
if $t == "Bash" then ($i.description // ("Running: " + (($i.command // "") | tostring | .[0:80])))
|
|
4743
|
+
elif $t == "Edit" then ("Editing " + base($i.file_path // $i.filePath // "a file"))
|
|
4744
|
+
elif $t == "MultiEdit" then ("Editing " + base($i.file_path // $i.filePath // "a file"))
|
|
4745
|
+
elif $t == "Write" then ("Writing " + base($i.file_path // $i.filePath // "a file"))
|
|
4746
|
+
elif $t == "NotebookEdit" then ("Editing " + base($i.notebook_path // "a notebook"))
|
|
4747
|
+
elif $t == "Read" then ("Reading " + base($i.file_path // $i.filePath // "a file"))
|
|
4748
|
+
elif $t == "Grep" then ("Searching for " + (($i.pattern // "") | tostring | .[0:60]))
|
|
4749
|
+
elif $t == "Glob" then ("Finding files: " + (($i.pattern // "") | tostring | .[0:60]))
|
|
4750
|
+
elif $t == "WebSearch" then ("Searching the web: " + (($i.query // "") | tostring | .[0:60]))
|
|
4751
|
+
elif $t == "WebFetch" then ("Fetching " + (($i.url // "") | tostring | .[0:80]))
|
|
4752
|
+
elif ($t == "Task" or $t == "Agent") then ("Working on: " + (($i.description // "a subtask") | tostring | .[0:80]))
|
|
4753
|
+
elif ($t | startswith("mcp__")) then ("Using " + ($t | sub("^mcp__"; "") | gsub("__"; " / ")))
|
|
4754
|
+
else ("Working (" + $t + ")")
|
|
4755
|
+
end
|
|
4756
|
+
' 2>/dev/null || true)"
|
|
4757
|
+
STEP="$(printf '%s' "$STEP" | tr '\\n\\t' ' ' | sed 's/ */ /g' | cut -c1-240)"
|
|
4758
|
+
[ -n "$STEP" ] || exit 0
|
|
4759
|
+
|
|
4760
|
+
# Stamp BEFORE the network call so a slow API can't unthrottle us.
|
|
4761
|
+
printf '%s' "$NOW" > "$STAMP" 2>/dev/null || true
|
|
4762
|
+
|
|
4763
|
+
# Bearer JWT (exchange tlk_ -> JWT, cached with expiry).
|
|
4764
|
+
TOKEN_FILE="$STATE_DIR/token"
|
|
4765
|
+
TOKEN=""
|
|
4766
|
+
if [ -f "$TOKEN_FILE" ]; then
|
|
4767
|
+
T_EXP="$(jq -r '.exp // 0' "$TOKEN_FILE" 2>/dev/null || echo 0)"
|
|
4768
|
+
case "$T_EXP" in ''|*[!0-9]*) T_EXP=0 ;; esac
|
|
4769
|
+
[ $(( T_EXP - NOW )) -gt 300 ] && TOKEN="$(jq -r '.token // empty' "$TOKEN_FILE" 2>/dev/null || true)"
|
|
4770
|
+
fi
|
|
4771
|
+
if [ -z "$TOKEN" ]; then
|
|
4772
|
+
EX="$(curl -fsS --max-time 5 -X POST "$HOST/host/exchange" \\
|
|
4773
|
+
-H 'Content-Type: application/json' \\
|
|
4774
|
+
-d "{\\"host_key\\":\\"$KEY\\"}" 2>/dev/null || true)"
|
|
4775
|
+
TOKEN="$(printf '%s' "$EX" | jq -r '.token // empty' 2>/dev/null || true)"
|
|
4776
|
+
[ -n "$TOKEN" ] || exit 0
|
|
4777
|
+
EXP_ISO="$(printf '%s' "$EX" | jq -r '.expires_at // empty' 2>/dev/null || true)"
|
|
4778
|
+
# GNU date (Linux hosts) first, then BSD date (macOS dev machines), then a
|
|
4779
|
+
# safe 30-min fallback so a parse miss doesn't poison the token cache.
|
|
4780
|
+
EXP_EPOCH="$(date -d "$EXP_ISO" +%s 2>/dev/null \\
|
|
4781
|
+
|| date -j -f '%Y-%m-%dT%H:%M:%SZ' "$EXP_ISO" +%s 2>/dev/null \\
|
|
4782
|
+
|| echo $(( NOW + 1800 )))"
|
|
4783
|
+
( umask 177; printf '{"token":"%s","exp":%s}' "$TOKEN" "$EXP_EPOCH" > "$TOKEN_FILE" 2>/dev/null || true )
|
|
4784
|
+
fi
|
|
4785
|
+
|
|
4786
|
+
# Fire-and-forget the push (never block the agent's tool flow).
|
|
4787
|
+
BODY="$(jq -nc --arg a "$AGENT_ID" --arg s "$STEP" '{agent_id:$a, step:$s}' 2>/dev/null || printf '{"agent_id":"%s","step":"%s"}' "$AGENT_ID" "$STEP")"
|
|
4788
|
+
( curl -fsS --max-time 4 -X POST "$HOST/host/kanban/auto-progress" \\
|
|
4789
|
+
-H 'Content-Type: application/json' \\
|
|
4790
|
+
-H "Authorization: Bearer $TOKEN" \\
|
|
4791
|
+
-d "$BODY" >/dev/null 2>&1 || true ) &
|
|
4792
|
+
|
|
4793
|
+
exit 0
|
|
4794
|
+
`;
|
|
4795
|
+
writeFileSync5(hookScriptPath, hookScript, { mode: 493 });
|
|
4796
|
+
const settingsPath = join4(claudeDir, "settings.local.json");
|
|
4797
|
+
let settings = {};
|
|
4798
|
+
try {
|
|
4799
|
+
settings = JSON.parse(readFileSync5(settingsPath, "utf-8"));
|
|
4800
|
+
} catch {
|
|
4801
|
+
}
|
|
4802
|
+
const hooks = settings["hooks"] ?? {};
|
|
4803
|
+
hooks["PostToolUse"] = [
|
|
4804
|
+
{
|
|
4805
|
+
hooks: [
|
|
4806
|
+
{ type: "command", command: hookScriptPath }
|
|
4807
|
+
]
|
|
4808
|
+
}
|
|
4809
|
+
];
|
|
4810
|
+
settings["hooks"] = hooks;
|
|
4811
|
+
writeFileSync5(settingsPath, JSON.stringify(settings, null, 2));
|
|
4812
|
+
}
|
|
4636
4813
|
function provisionOrientHook(codeName) {
|
|
4637
4814
|
const projectDir = getProjectDir(codeName);
|
|
4638
4815
|
const claudeDir = join4(projectDir, ".claude");
|
|
@@ -4746,6 +4923,11 @@ var SECRETS_DENY_PERMISSIONS = [
|
|
|
4746
4923
|
"Read(**/credentials/**)",
|
|
4747
4924
|
"Read(**/credentials.json)",
|
|
4748
4925
|
"Read(**/.aws/**)",
|
|
4926
|
+
// gcloud stores ADC + cached access/refresh tokens under ~/.config/gcloud/
|
|
4927
|
+
// (application_default_credentials.json, credentials.db, access_tokens.db).
|
|
4928
|
+
// Brokered GCP access flows via CLOUDSDK_AUTH_ACCESS_TOKEN env, never these
|
|
4929
|
+
// files, so denying reads here is the GCP analogue of the .aws/ block.
|
|
4930
|
+
"Read(**/.config/gcloud/**)",
|
|
4749
4931
|
"Read(**/.ssh/**)",
|
|
4750
4932
|
"Read(**/config/database.yml)",
|
|
4751
4933
|
"Read(**/config/credentials.json)",
|
|
@@ -5018,6 +5200,12 @@ function buildMcpJson(input) {
|
|
|
5018
5200
|
// dashboard links) in tool replies. Falls back to NEXT_PUBLIC_APP_URL
|
|
5019
5201
|
// / AGT_CONSOLE_URL — same chain consoleUrl uses for kanban links.
|
|
5020
5202
|
AGT_APP_URL: process.env["AGT_APP_URL"] ?? process.env["NEXT_PUBLIC_APP_URL"] ?? process.env["AGT_CONSOLE_URL"] ?? "",
|
|
5203
|
+
// ENG-6229: arms the in-session `request_restart` self-restart tool.
|
|
5204
|
+
// Read at provision time from the manager's env (like AGT_HOST above),
|
|
5205
|
+
// NOT a per-spawn `${...}` template — it's a host-level gate. Empty by
|
|
5206
|
+
// default ⇒ the tool isn't registered at all (ships dark). When an
|
|
5207
|
+
// operator sets it on the host, the next /host/refresh bakes it in.
|
|
5208
|
+
AGT_AGENT_SELF_RESTART_ENABLED: process.env["AGT_AGENT_SELF_RESTART_ENABLED"] ?? "",
|
|
5021
5209
|
// Include PATH/HOME so the MCP subprocess can resolve binaries
|
|
5022
5210
|
PATH: process.env["PATH"] ?? "",
|
|
5023
5211
|
HOME: process.env["HOME"] ?? ""
|
|
@@ -5034,6 +5222,7 @@ function buildMcpJson(input) {
|
|
|
5034
5222
|
integration
|
|
5035
5223
|
});
|
|
5036
5224
|
}
|
|
5225
|
+
const hasXeroBroker = input.integrations?.some((i) => i.definition_id === "xero-broker") ?? false;
|
|
5037
5226
|
const xeroIntegration = input.integrations?.find((i) => i.definition_id === "xero");
|
|
5038
5227
|
if (xeroIntegration) {
|
|
5039
5228
|
const brokerMode = Boolean(xeroIntegration.id);
|
|
@@ -5048,6 +5237,8 @@ function buildMcpJson(input) {
|
|
|
5048
5237
|
AGT_API_KEY: "${AGT_API_KEY}",
|
|
5049
5238
|
AGT_AGENT_ID: input.agent.agent_id,
|
|
5050
5239
|
...brokerMode ? { AGT_INTEGRATION_ID: xeroIntegration.id } : {},
|
|
5240
|
+
// ENG-4922: writes go through xero-broker → read-only vendor server.
|
|
5241
|
+
...hasXeroBroker ? { XERO_WRITES_VIA_BROKER: "true" } : {},
|
|
5051
5242
|
PATH: process.env["PATH"] ?? "",
|
|
5052
5243
|
HOME: process.env["HOME"] ?? ""
|
|
5053
5244
|
}
|
|
@@ -5086,6 +5277,34 @@ function buildMcpJson(input) {
|
|
|
5086
5277
|
}
|
|
5087
5278
|
};
|
|
5088
5279
|
}
|
|
5280
|
+
if (hasXeroBroker) {
|
|
5281
|
+
mcpServers["xero-broker"] = {
|
|
5282
|
+
command: "npx",
|
|
5283
|
+
args: ["-y", "@integrity-labs/xero-broker@latest"],
|
|
5284
|
+
env: {
|
|
5285
|
+
AGT_HOST: "${AGT_HOST}",
|
|
5286
|
+
AGT_AGENT_ID: input.agent.agent_id,
|
|
5287
|
+
AGT_RUN_ID: "${AGT_RUN_ID}",
|
|
5288
|
+
AGT_API_KEY: "${AGT_API_KEY}",
|
|
5289
|
+
PATH: process.env["PATH"] ?? "",
|
|
5290
|
+
HOME: process.env["HOME"] ?? ""
|
|
5291
|
+
}
|
|
5292
|
+
};
|
|
5293
|
+
}
|
|
5294
|
+
const hasAdminDebug = input.integrations?.some((i) => i.definition_id === "augmented-admin") ?? false;
|
|
5295
|
+
if (hasAdminDebug) {
|
|
5296
|
+
const localAdminMcpPath = join4(getHomeDir3(), ".augmented", "_mcp", "augmented-admin.js");
|
|
5297
|
+
mcpServers["augmented-admin"] = {
|
|
5298
|
+
command: "node",
|
|
5299
|
+
args: [localAdminMcpPath],
|
|
5300
|
+
env: {
|
|
5301
|
+
AGT_HOST: "${AGT_HOST}",
|
|
5302
|
+
AGT_AGENT_ID: input.agent.agent_id,
|
|
5303
|
+
AGT_RUN_ID: "${AGT_RUN_ID}",
|
|
5304
|
+
AGT_API_KEY: "${AGT_API_KEY}"
|
|
5305
|
+
}
|
|
5306
|
+
};
|
|
5307
|
+
}
|
|
5089
5308
|
return { mcpServers };
|
|
5090
5309
|
}
|
|
5091
5310
|
function parseIntervalMinutes(scheduleEvery) {
|
|
@@ -5545,6 +5764,7 @@ ${sections}`
|
|
|
5545
5764
|
}
|
|
5546
5765
|
});
|
|
5547
5766
|
const localSlackChannel = join4(getHomeDir3(), ".augmented", "_mcp", "slack-channel.js");
|
|
5767
|
+
const slackAvatarEnvUrl = resolveAvatarEnvUrl(options?.agentAvatarUrl).url;
|
|
5548
5768
|
const slackEntry = {
|
|
5549
5769
|
command: existsSync5(localSlackChannel) ? "node" : "npx",
|
|
5550
5770
|
args: existsSync5(localSlackChannel) ? [localSlackChannel] : ["-y", "@augmented/claude-code-channel-slack"],
|
|
@@ -5562,6 +5782,13 @@ ${sections}`
|
|
|
5562
5782
|
...slackPeerEnv,
|
|
5563
5783
|
...slackAgtAuthEnv,
|
|
5564
5784
|
...tzEnv,
|
|
5785
|
+
// ENG-6155: the agent's avatar URL (public 512×512 JPG). The
|
|
5786
|
+
// slack-channel MCP sets it as the bot's Slack profile photo on
|
|
5787
|
+
// first connect (users.setPhoto). Omitted when absent so the bot
|
|
5788
|
+
// keeps its current photo; the URL's cache-bust param changes on
|
|
5789
|
+
// re-generation, so the MCP re-applies a new avatar.
|
|
5790
|
+
// ENG-6245: slackAvatarEnvUrl is null for data-URI / oversized values.
|
|
5791
|
+
...slackAvatarEnvUrl ? { SLACK_AGENT_AVATAR_URL: slackAvatarEnvUrl } : {},
|
|
5565
5792
|
// ENG-4940: channel-agnostic peer kill switch — same enum
|
|
5566
5793
|
// as the Telegram path emits above. The Slack classifier
|
|
5567
5794
|
// (ENG-4936) honours PEER_DISABLED with identical
|
|
@@ -5717,6 +5944,7 @@ ${sections}`
|
|
|
5717
5944
|
...appToken ? { SLACK_APP_TOKEN: appToken } : {}
|
|
5718
5945
|
}
|
|
5719
5946
|
});
|
|
5947
|
+
const slackAvatarEnvUrl = resolveAvatarEnvUrl(options?.agentAvatarUrl).url;
|
|
5720
5948
|
if (isPersistent && existsSync5(localSlackChannel)) {
|
|
5721
5949
|
mcpServers["slack"] = {
|
|
5722
5950
|
command: "node",
|
|
@@ -5730,7 +5958,11 @@ ${sections}`
|
|
|
5730
5958
|
...oneshotBlockKitEnv,
|
|
5731
5959
|
...slackPeerEnv,
|
|
5732
5960
|
...slackAgtAuthEnv,
|
|
5733
|
-
...tzEnv
|
|
5961
|
+
...tzEnv,
|
|
5962
|
+
// ENG-6155: avatar URL → bot Slack profile photo (see persistent
|
|
5963
|
+
// branch above). Mirrored here so oneshot-mode agents get it too.
|
|
5964
|
+
// ENG-6245: slackAvatarEnvUrl is null for data-URI / oversized values.
|
|
5965
|
+
...slackAvatarEnvUrl ? { SLACK_AGENT_AVATAR_URL: slackAvatarEnvUrl } : {}
|
|
5734
5966
|
}
|
|
5735
5967
|
};
|
|
5736
5968
|
} else {
|
|
@@ -5746,7 +5978,11 @@ ${sections}`
|
|
|
5746
5978
|
...oneshotBlockKitEnv,
|
|
5747
5979
|
...slackPeerEnv,
|
|
5748
5980
|
...slackAgtAuthEnv,
|
|
5749
|
-
...tzEnv
|
|
5981
|
+
...tzEnv,
|
|
5982
|
+
// ENG-6155: avatar URL → bot Slack profile photo (see persistent
|
|
5983
|
+
// branch above). Mirrored here so oneshot-mode agents get it too.
|
|
5984
|
+
// ENG-6245: slackAvatarEnvUrl is null for data-URI / oversized values.
|
|
5985
|
+
...slackAvatarEnvUrl ? { SLACK_AGENT_AVATAR_URL: slackAvatarEnvUrl } : {}
|
|
5750
5986
|
}
|
|
5751
5987
|
};
|
|
5752
5988
|
}
|
|
@@ -5915,15 +6151,30 @@ ${sections}`
|
|
|
5915
6151
|
for (const integration of decryptedIntegrations) {
|
|
5916
6152
|
const prefix = integration.definition_id.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
5917
6153
|
const creds = integration.credentials;
|
|
6154
|
+
const def = INTEGRATION_REGISTRY.find((d) => d.id === integration.definition_id);
|
|
6155
|
+
let token;
|
|
5918
6156
|
if (integration.auth_type === "oauth2") {
|
|
5919
|
-
|
|
5920
|
-
if (
|
|
5921
|
-
envUpdates[`${prefix}_ACCESS_TOKEN`] =
|
|
6157
|
+
token = creds.access_token;
|
|
6158
|
+
if (token) {
|
|
6159
|
+
envUpdates[`${prefix}_ACCESS_TOKEN`] = token;
|
|
5922
6160
|
}
|
|
5923
6161
|
} else if (integration.auth_type === "api_key") {
|
|
5924
|
-
|
|
5925
|
-
if (
|
|
5926
|
-
envUpdates[`${prefix}_API_KEY`] =
|
|
6162
|
+
token = creds.api_key;
|
|
6163
|
+
if (token) {
|
|
6164
|
+
envUpdates[`${prefix}_API_KEY`] = token;
|
|
6165
|
+
}
|
|
6166
|
+
}
|
|
6167
|
+
if (def?.cli_tool) {
|
|
6168
|
+
const { env_key, extra_env } = def.cli_tool;
|
|
6169
|
+
if (env_key && token && !(env_key in envUpdates)) {
|
|
6170
|
+
envUpdates[env_key] = token;
|
|
6171
|
+
}
|
|
6172
|
+
if (extra_env) {
|
|
6173
|
+
for (const [k, v] of Object.entries(extra_env)) {
|
|
6174
|
+
if (typeof v === "string" && v && !(k in envUpdates)) {
|
|
6175
|
+
envUpdates[k] = v;
|
|
6176
|
+
}
|
|
6177
|
+
}
|
|
5927
6178
|
}
|
|
5928
6179
|
}
|
|
5929
6180
|
if (integration.config) {
|
|
@@ -5964,12 +6215,15 @@ ${sections}`
|
|
|
5964
6215
|
integration
|
|
5965
6216
|
}));
|
|
5966
6217
|
}
|
|
6218
|
+
const hasXeroBroker = integrations.some((i) => i.definition_id === "xero-broker");
|
|
5967
6219
|
const xeroIntegration = integrations.find((i) => i.definition_id === "xero");
|
|
5968
6220
|
if (xeroIntegration) {
|
|
5969
6221
|
const brokerMode = Boolean(agentId && xeroIntegration.id);
|
|
5970
6222
|
const xeroEnv = {
|
|
5971
6223
|
...brokerMode ? {} : { XERO_CLIENT_BEARER_TOKEN: "${XERO_ACCESS_TOKEN}" },
|
|
5972
6224
|
XERO_TENANT_ID: "${XERO_TENANT_ID}",
|
|
6225
|
+
// ENG-4922: writes go through xero-broker → read-only vendor server.
|
|
6226
|
+
...hasXeroBroker ? { XERO_WRITES_VIA_BROKER: "true" } : {},
|
|
5973
6227
|
PATH: process.env["PATH"] ?? "",
|
|
5974
6228
|
HOME: process.env["HOME"] ?? ""
|
|
5975
6229
|
};
|
|
@@ -6020,12 +6274,48 @@ ${sections}`
|
|
|
6020
6274
|
});
|
|
6021
6275
|
}
|
|
6022
6276
|
}
|
|
6277
|
+
if (hasXeroBroker) {
|
|
6278
|
+
const brokerAgentId = resolveBrokerAgentId(codeName);
|
|
6279
|
+
if (!brokerAgentId) {
|
|
6280
|
+
process.stderr.write(`[manager-worker] [xero-broker] skipping write for '${codeName}': no real AGT_AGENT_ID available. The full-provision artifact pipeline will recreate this on the next cycle.
|
|
6281
|
+
`);
|
|
6282
|
+
} else {
|
|
6283
|
+
this.writeMcpServer(codeName, "xero-broker", {
|
|
6284
|
+
command: "npx",
|
|
6285
|
+
args: ["-y", "@integrity-labs/xero-broker@latest"],
|
|
6286
|
+
env: {
|
|
6287
|
+
AGT_HOST: "${AGT_HOST}",
|
|
6288
|
+
AGT_API_KEY: "${AGT_API_KEY}",
|
|
6289
|
+
AGT_AGENT_ID: brokerAgentId,
|
|
6290
|
+
AGT_RUN_ID: "${AGT_RUN_ID}",
|
|
6291
|
+
PATH: process.env["PATH"] ?? "",
|
|
6292
|
+
HOME: process.env["HOME"] ?? ""
|
|
6293
|
+
}
|
|
6294
|
+
});
|
|
6295
|
+
}
|
|
6296
|
+
}
|
|
6297
|
+
const hasAdminDebug = integrations.some((i) => i.definition_id === "augmented-admin");
|
|
6298
|
+
if (hasAdminDebug) {
|
|
6299
|
+
const localAdminMcpPath = join4(getHomeDir3(), ".augmented", "_mcp", "augmented-admin.js");
|
|
6300
|
+
this.writeMcpServer(codeName, "augmented-admin", {
|
|
6301
|
+
command: "node",
|
|
6302
|
+
args: [localAdminMcpPath],
|
|
6303
|
+
env: {
|
|
6304
|
+
AGT_HOST: "${AGT_HOST}",
|
|
6305
|
+
AGT_AGENT_ID: resolveBrokerAgentId(codeName) ?? agentId ?? "",
|
|
6306
|
+
AGT_RUN_ID: "${AGT_RUN_ID}",
|
|
6307
|
+
AGT_API_KEY: "${AGT_API_KEY}"
|
|
6308
|
+
}
|
|
6309
|
+
});
|
|
6310
|
+
}
|
|
6023
6311
|
if (this.removeMcpServer) {
|
|
6024
6312
|
const nativeMcpKeys = INTEGRATION_REGISTRY.filter((d) => d.nativeMcp !== void 0).map((d) => d.nativeMcp.key ?? d.id);
|
|
6025
6313
|
const integrationDerivedKeys = /* @__PURE__ */ new Set([
|
|
6026
6314
|
"xero",
|
|
6027
6315
|
"postiz",
|
|
6028
6316
|
"cloud-broker",
|
|
6317
|
+
"xero-broker",
|
|
6318
|
+
"augmented-admin",
|
|
6029
6319
|
...nativeMcpKeys,
|
|
6030
6320
|
...Object.entries(OAUTH_PROVIDERS).filter(([, provider]) => Boolean(provider.mcpUrl)).map(([id]) => id)
|
|
6031
6321
|
]);
|
|
@@ -6036,6 +6326,10 @@ ${sections}`
|
|
|
6036
6326
|
expectedKeys.add("postiz");
|
|
6037
6327
|
if (hasCloudBroker)
|
|
6038
6328
|
expectedKeys.add("cloud-broker");
|
|
6329
|
+
if (hasXeroBroker)
|
|
6330
|
+
expectedKeys.add("xero-broker");
|
|
6331
|
+
if (hasAdminDebug)
|
|
6332
|
+
expectedKeys.add("augmented-admin");
|
|
6039
6333
|
for (const integration of integrations) {
|
|
6040
6334
|
const def = INTEGRATION_REGISTRY.find((d) => d.id === integration.definition_id);
|
|
6041
6335
|
if (def?.nativeMcp) {
|
|
@@ -7555,6 +7849,7 @@ export {
|
|
|
7555
7849
|
CHANNEL_SECRET_ENV_KEYS,
|
|
7556
7850
|
provisionStopHook,
|
|
7557
7851
|
provisionIsolationHook,
|
|
7852
|
+
provisionAutoKanbanProgressHook,
|
|
7558
7853
|
provisionOrientHook,
|
|
7559
7854
|
setJsonMode,
|
|
7560
7855
|
isJsonMode,
|
|
@@ -7586,4 +7881,4 @@ export {
|
|
|
7586
7881
|
managerInstallSystemUnitCommand,
|
|
7587
7882
|
managerUninstallSystemUnitCommand
|
|
7588
7883
|
};
|
|
7589
|
-
//# sourceMappingURL=chunk-
|
|
7884
|
+
//# sourceMappingURL=chunk-R7NKCGWN.js.map
|