@agentdeploymentco/bishop 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.js +4 -4
- package/dist/slack/destination.js +1 -1
- package/dist/slack/members.js +1 -1
- package/dist/slack/mentions.js +1 -1
- package/package.json +3 -3
package/dist/config.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{mkdir as
|
|
2
|
-
`)}async function nt(n=process.cwd()){const o=w(n);let e;try{e=await
|
|
3
|
-
${J(
|
|
4
|
-
`,"utf8"),e}function
|
|
1
|
+
import{mkdir as v,readFile as y,writeFile as O}from"node:fs/promises";import{dirname as j,join as $}from"node:path";import{z as t}from"zod";import{BishopError as c}from"./errors.js";const E=".bishop",R="config.json",I=t.strictObject({id:t.string().optional(),name:t.string().min(1),displayName:t.string().optional(),description:t.string().optional()}),N=["low","medium","high"],K="high",h=t.string().transform(n=>n.trim().toLowerCase()).pipe(t.enum(N)),S=t.strictObject({workspace:t.string().optional(),app:I.optional(),verbosity:h.optional(),allow:t.array(t.string().min(1)).optional(),maxBotTurns:t.number().int().nonnegative().optional()}),A=t.strictObject({allow:t.array(t.string().min(1)).optional(),pollSeconds:t.number().int().positive().optional(),labelPrefix:t.string().trim().min(1).optional(),markRead:t.boolean().optional(),internalDomains:t.array(t.string().trim().toLowerCase().regex(/^[^\s@]+\.[^\s@]+$/,"must be a domain like example.com")).optional()}),C=t.strictObject({cert:t.string().trim().min(1),key:t.string().trim().min(1)}),_=t.strictObject({id:t.string().optional(),name:t.string().min(1),displayName:t.string().optional(),description:t.string().optional()}),F=t.strictObject({app:_.optional(),allow:t.array(t.string().min(1)).optional(),verbosity:h.optional(),port:t.number().int().min(1).max(65535).optional(),host:t.string().trim().min(1).optional(),tls:C.optional()}),p=["claude","codex"],T=t.union([t.literal(!1),t.strictObject({idleMinutes:t.number().positive().max(10080).optional(),max:t.number().int().positive().optional()})]),L=t.strictObject({model:t.string().trim().min(1).optional(),effort:t.string().trim().min(1).optional(),options:t.record(t.string(),t.unknown()).optional(),keepAlive:T.optional()}),z=t.strictObject({harness:t.enum(p).optional(),model:t.string().trim().min(1).optional(),effort:t.string().trim().min(1).optional(),harnesses:t.partialRecord(t.enum(p),L,{error:()=>`not a harness Bishop runs; supported: ${p.join(", ")}`}).superRefine((n,o)=>{n.codex?.keepAlive!==void 0&&o.addIssue({code:"custom",path:["codex","keepAlive"],message:"only the claude harness keeps an agent running between turns"})}).optional(),worktrees:t.boolean().optional(),projectSettings:t.boolean().optional(),sandbox:t.union([t.boolean(),t.strictObject({profile:t.string().trim().min(1).optional()})]).optional(),options:t.record(t.string(),t.unknown()).optional()}),B=t.strictObject({maxAgeDays:t.number().int().positive().optional()}),D=t.strictObject({maxMb:t.number().positive().optional()}),U=["all","external"],V=["reject","approve"],b=t.strictObject({scope:t.enum(U).optional(),onError:t.enum(V).optional()});function G(n){let o;try{o=new URL(n)}catch{return!1}return o.protocol==="https:"?!0:o.protocol!=="http:"?!1:o.hostname==="localhost"||o.hostname==="[::1]"||/^127(\.\d{1,3}){3}$/.test(o.hostname)}const P=t.strictObject({command:t.array(t.string().min(1)).min(1).optional(),url:t.string().trim().refine(G,"must be an https URL, or http on loopback").optional(),inbound:b.optional(),outbound:b.optional(),timeoutSeconds:t.number().positive().max(300).optional(),env:t.array(t.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/,"must be an environment variable name")).optional()}).superRefine((n,o)=>{n.command&&n.url?o.addIssue({code:"custom",message:"names both command and url; pick one"}):!n.command&&!n.url&&o.addIssue({code:"custom",message:"needs a command or a url"}),n.url&&n.env&&o.addIssue({code:"custom",path:["env"],message:"is only for a command reviewer"}),!n.inbound&&!n.outbound&&o.addIssue({code:"custom",message:"reviews nothing without inbound or outbound"})}),H=t.strictObject({slack:S.optional(),gmail:A.optional(),teams:F.optional(),agent:z.optional(),files:D.optional(),gc:B.optional(),review:P.optional()}).superRefine((n,o)=>{n.review&&!n.agent?.sandbox&&o.addIssue({code:"custom",path:["review"],message:"needs agent.sandbox on"})});class m extends c{path;constructor(o,e){super(o,"ConfigError"),this.path=e}}function q(n,o={}){const e=n.agent,i=e?.harness??"claude",r=o.harness??i,s=e?.harnesses?.[r],{keepAlive:x,...k}=s??{},a=s&&Object.keys(k).length>0?s:void 0,l=[];e?.options&&(a&&r===i?l.push({kind:"options-replaced",harness:r}):!a&&r!==i&&l.push({kind:"options-foreign",harness:r,configured:i}));const u=o.model??a?.model??e?.model,d=o.effort??a?.effort??e?.effort,g=a?a.options:e?.options,f=r==="claude"?x:void 0;return{harness:r,...u?{model:u}:{},...d?{effort:d}:{},...g?{options:g}:{},...f!==void 0?{keepAlive:f}:{},warnings:l}}function Q(n){const o=n.agent?.sandbox;if(o)return o===!0||!o.profile?{}:{profile:o.profile}}function X(n){return o=>{const e=o.trim();if(!e)throw new c(`${n} needs a value`);return e}}function tt(n){return o=>{const e=Number(o.trim());if(!Number.isInteger(e)||e<=0)throw new c(`${n} needs a positive whole number, got "${o}"`);return e}}function ot(n){const o=n.trim();if(p.includes(o))return o;throw new c(`unknown harness "${n}"; supported: ${p.join(", ")}`)}function w(n=process.cwd()){return $(n,E,R)}function J(n){return n.issues.flatMap(o=>{if(o.code==="unrecognized_keys"&&o.keys.length>0){const e=o.message.startsWith("Unrecognized key")?"unrecognized key":o.message;return o.keys.map(i=>`${[...o.path,i].join(".")}: ${e}`)}return[`${o.path.length>0?o.path.join("."):"(root)"}: ${o.message}`]}).join(`
|
|
2
|
+
`)}async function nt(n=process.cwd()){const o=w(n);let e;try{e=await y(o,"utf8")}catch(s){if(s.code==="ENOENT")return{};throw new m(`Couldn't read ${o}: ${s.message}`,o)}let i;try{i=JSON.parse(e)}catch(s){throw new m(`${o} isn't valid JSON: ${s.message}`,o)}const r=H.safeParse(i);if(!r.success)throw new m(`${o} has invalid values:
|
|
3
|
+
${J(r.error)}`,o);return r.data}async function et(n,o=process.cwd()){const e=w(o);return await v(j(e),{recursive:!0}),await O(e,`${JSON.stringify(n,null,2)}
|
|
4
|
+
`,"utf8"),e}function rt(n){return n.displayName?.trim()||n.name}export{E as CONFIG_DIR,R as CONFIG_FILE,m as ConfigError,H as ConfigSchema,K as DEFAULT_VERBOSITY,p as HARNESSES,V as REVIEW_ON_ERROR,U as REVIEW_SCOPES,N as VERBOSITY,w as configPath,rt as displayNameOf,nt as loadConfig,X as nonEmptyFlag,ot as parseHarnessName,tt as positiveIntFlag,q as resolveAgent,Q as sandboxConfig,et as writeConfig};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BishopError as l}from"../errors.js";import{log as p}from"../log.js";import{retry as
|
|
1
|
+
import{BishopError as l}from"../errors.js";import{log as p}from"../log.js";import{retry as w}from"../retry.js";import{splitForSlack as y}from"./format.js";import{attachToSlack as S}from"./upload.js";function m(e){return e.threadTs?`${e.channel}:${e.threadTs}`:e.channel}function k(e){const[n,a]=e.split(":");if(!n)throw new l(`not a Slack destination: ${e}`);return{channel:n,...a?{threadTs:a}:{}}}function v(e){return/^[CG][A-Z0-9]{2,}$/.test(e)}function x(e){return/^D[A-Z0-9]{2,}$/.test(e)}function $(e){return/^[UW][A-Z0-9]{2,}$/.test(e)}const T=new Set(["ratelimited","rate_limited"]);function _(e){const n=e;if(!n)return!1;if(n.code==="slack_webapi_rate_limited_error")return{...n.retryAfter?{retryAfterMs:n.retryAfter*1e3}:{}};const a=n.data?.error;return!!(a&&T.has(a))}async function L(e,n){const{channel:a,threadTs:r}=k(n.handle),d=y(n.text),s=n.files??[],t=s.length>0?d.pop()??"":void 0;let c;for(const f of d){const i=r??c,h=await w(()=>e.chat.postMessage({channel:a,markdown_text:f,...i?{thread_ts:i}:{}}),{what:"chat.postMessage",retryable:_});c??=h.ts}const o=r??c;if(t!==void 0){const f={channel:a,...o?{threadTs:o}:{}};try{const i=await S(e,f,s,t);if(c??=i?.ts,!i&&t){const h=await w(()=>e.chat.postMessage({channel:a,markdown_text:t,...o?{thread_ts:o}:{}}),{what:"chat.postMessage",retryable:_});c??=h.ts}}catch(i){const h=s.map(u=>u.name).join(", ");p.error({channel:a,files:h,err:i},"could not send a file with a report");for(const u of[t,`_Could not upload ${h}._`]){if(!u)continue;const g=await e.chat.postMessage({channel:a,markdown_text:u,...o?{thread_ts:o}:{}}).catch(()=>{});c??=g?.ts}}}return p.info({channel:a,...o?{thread:o}:{},parts:d.length},"delivered to Slack"),r||!c?void 0:{channel:a,threadTs:c}}async function F(e,n){const{channel:a,threadTs:r}=k(n),d=r?" (thread)":"";try{const t=(await e.conversations.info({channel:a})).channel;if(t?.name)return`#${t.name}${d}`;if(t?.is_im&&t.user){const o=(await e.users.info({user:t.user})).user,f=o?.profile?.display_name?.trim()||(o?.is_bot?o.profile?.real_name?.trim():void 0)||o?.name;if(f)return`@${f}`}}catch(s){p.debug({channel:a,err:s},"could not name a Slack destination")}return`${a}${d}`}async function A(e,n){const a=n.toLowerCase();for await(const r of e.paginate("conversations.list",{types:"public_channel,private_channel",exclude_archived:!0,limit:200})){const s=(r.channels??[]).find(t=>t.name?.toLowerCase()===a);if(s)return s}}async function C(e,n){const a=n.toLowerCase();if(a.includes("@"))try{const r=await e.users.lookupByEmail({email:n});if(r.user?.id)return r.user.id}catch(r){p.debug({email:n,err:r},"no Slack user with that address")}for await(const r of e.paginate("users.list",{limit:200})){const d=r.members??[];for(const s of d){if(s.deleted||!s.id)continue;if([s.name,s.profile?.display_name,s.profile?.real_name].some(c=>c?.toLowerCase()===a))return s.id}}}async function R(e,n,a={}){try{return await I(e,n,a)}catch(r){throw r instanceof l?r:M(r,n)}}function M(e,n){const a=e,r=a?.data?.error;return r==="missing_scope"?new l(`Slack won't let this app look up ${n}: it is missing the ${a?.data?.needed??"required"} scope. Bishop's manifest asks for it, so an app installed before this existed has to be reinstalled: run \`bishop slack setup\` again.`):new l(`Slack could not resolve ${n}: ${r??(e instanceof Error?e.message:String(e))}`)}async function I(e,n,a){const r=n.trim();if(!r)throw new l("a Slack destination needs a channel or a person");const[d,s]=r.split(":"),t=(d??"").replace(/^[#@]/,"");if(!t)throw new l(`not a Slack destination: ${n}`);const c=r.startsWith("@")||$(t);if(x(t))return{interface:"slack",handle:m({channel:t,...s?{threadTs:s}:{}}),label:t};if(v(t)){const i=(await e.conversations.info({channel:t})).channel;if(!i?.id)throw new l(`Slack has no conversation ${t}`);return b(i,t),{interface:"slack",handle:m({channel:i.id,...s?{threadTs:s}:{}}),label:i.name?`#${i.name}`:i.id}}if(c){const f=$(t)?t:await C(e,t);if(!f)throw new l(`no Slack user matches @${t}`);if(a.allows&&!a.allows(f))throw new l(`@${t} is not on this agent's allow list, so Bishop won't start sending them messages they never asked for. Add them to slack.allow in .bishop/config.json, or post to a channel they are in instead.`);const h=(await e.conversations.open({users:f})).channel?.id;if(!h)throw new l(`could not open a DM with @${t}`);return{interface:"slack",handle:m({channel:h,...s?{threadTs:s}:{}}),label:`@${t}`}}const o=await A(e,t);if(!o?.id)throw new l(`no Slack channel named #${t} that this app can see. A private channel has to have the app in it.`);return b(o,`#${t}`),{interface:"slack",handle:m({channel:o.id,...s?{threadTs:s}:{}}),label:`#${o.name??t}`}}function b(e,n){if(!(e.is_im||e.is_member!==!1))throw new l(`this app is not in ${n}. Invite it there first, or nothing sent to it will arrive.`)}export{L as deliverToSlack,F as describeSlackHandle,k as parseSlackHandle,R as resolveSlackDestination,m as slackHandle,_ as slackRetryable};
|
package/dist/slack/members.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{log as a}from"../log.js";function d(t){const
|
|
1
|
+
import{log as a}from"../log.js";function d(t){const o=t.profile?.display_name?.trim(),s=t.profile?.real_name?.trim(),e=t.profile?.email?.trim(),r=t.name?.trim(),i=t.enterprise_user?.enterprise_id,n=t.is_restricted||t.is_ultra_restricted||t.is_stranger;return{userId:t.id??"",...o?{displayName:o}:{},...s?{realName:s}:{},...e?{email:e}:{},...r?{handle:r}:{},...t.team_id?{teamId:t.team_id}:{},...i?{enterpriseId:i}:{},...n?{outsider:!0}:{},...t.is_bot?{bot:!0}:{}}}const l="USLACKBOT";function c(t){return!!t.id&&!t.deleted&&t.id!==l}async function p(t,o=()=>!0){const s=[];let e;do{const r=await t.users.list({limit:200,...e?{cursor:e}:{}});for(const i of r.members??[])i.id&&o(i)&&s.push(d(i));e=r.response_metadata?.next_cursor||void 0}while(e);return a.debug({users:s.length},"paged the workspace member list"),s}export{c as isMentionable,p as listMembers,d as toUser};
|
package/dist/slack/mentions.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{CODE as
|
|
1
|
+
import{CODE as b}from"../interface/mentions.js";import{log as f}from"../log.js";function L(e){const r=e.displayName?.trim();if(r&&!/\s/.test(r))return r;const n=e.bot?e.realName?.trim():void 0;if(n&&_.test(n))return n;const a=e.handle?.trim();return a&&!/\s/.test(a)?a:void 0}const E=2e3,w=/<@([UW][A-Z0-9]+)(?:\|([^>]*))?>|<!(here|channel|everyone)(?:\|[^>]*)?>|<!subteam\^([A-Z0-9]+)(?:\|([^>]*))?>|<#(C[A-Z0-9]+)(?:\|([^>]*))?>/g;async function P(e,r,n=E){return h(e,async()=>{const a=g(e,r).catch(()=>{});let o;const l=new Promise(t=>{o=setTimeout(()=>t(void 0),n)}),i=await Promise.race([a,l]);return clearTimeout(o),i!==void 0?i:(f.debug("naming the people mentioned took too long; using the labels Slack sent"),g(e,k))})}const A=/<((?:https?|mailto):[^|>\s]+)(?:\|([^>]*))?>/g;function R(e){return e.replace(A,(r,n,a)=>a?.trim()||I(n)).replaceAll("<","<").replaceAll(">",">").replaceAll("&","&")}function I(e){return e.startsWith("mailto:")?e.slice(7):e}const k={lookup:async e=>({userId:e}),findByName:async()=>{}};async function h(e,r){try{return await r()}catch(n){return f.debug({err:n},"could not translate mentions; passing the text through"),e}}async function g(e,r){const n=[...e.matchAll(w)];if(n.length===0)return e;const a=await Promise.all(n.map(async i=>{const[,t,c,s,u,d,p,N]=i;if(t){const m=await r.lookup(t),y=c?.trim().replace(/^@+/,"");return`@${L(m)||y||t}`}return s?`@${s}`:u?`@${d?.trim().replace(/^@+/,"")||u}`:p?`#${N?.trim().replace(/^#+/,"")||p}`:i[0]}));let o="",l=0;return n.forEach((i,t)=>{const c=i.index??0;o+=e.slice(l,c)+a[t],l=c+i[0].length}),o+e.slice(l)}const T=/(^|[^\p{L}\p{N}@/<])@([\p{L}\p{N}][\p{L}\p{N}._-]{0,79})/gu,_=/^[\p{L}\p{N}](?:[\p{L}\p{N}._-]{0,78}[\p{L}\p{N}])?$/u,$=new Set(["here","channel","everyone","group"]);async function W(e,r){return h(e,async()=>{const n=e.split(b);return(await Promise.all(n.map((o,l)=>l%2===1?o:O(o,r)))).join("")})}async function O(e,r){const n=[...e.matchAll(T)];if(n.length===0)return e;const a=await Promise.all(n.map(async t=>{const c=t[1]??"",s=t[2]??"",u=s.replace(/[._-]+$/,""),d=s.slice(u.length);if(!u||$.has(u.toLowerCase()))return t[0];const p=await r.findByName(u);return p?`${c}<@${p.userId}>${d}`:t[0]}));let o="",l=0;n.forEach((t,c)=>{const s=t.index??0;o+=e.slice(l,s)+a[c],l=s+t[0].length});const i=o+e.slice(l);return i!==e&&f.debug("linked a mention in agent text"),i}export{W as linkMentions,L as mentionableName,R as plainText,P as renderMentions};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentdeploymentco/bishop",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "An agent gateway. Connects an agent to Slack, email, and Microsoft Teams.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -45,10 +45,10 @@
|
|
|
45
45
|
"docs:preview": "npm --prefix docs run preview --"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@anthropic-ai/claude-agent-sdk": "0.3.
|
|
48
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.310",
|
|
49
49
|
"@microsoft/teams.apps": "^2.0.16",
|
|
50
50
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
51
|
-
"@openai/codex-sdk": "0.
|
|
51
|
+
"@openai/codex-sdk": "0.164.0",
|
|
52
52
|
"@slack/bolt": "^5.0.0",
|
|
53
53
|
"@slack/web-api": "^8",
|
|
54
54
|
"commander": "^13",
|