@heyquilt/seam 0.134.0 → 0.141.0
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/bin/seam.js +3 -0
- package/lib/quilts/cli.js +27 -4
- package/lib/quilts/client.js +14 -0
- package/lib/quilts/describe.js +30 -1
- package/lib/quilts/tools.js +26 -4
- package/package.json +1 -1
package/bin/seam.js
CHANGED
|
@@ -89,6 +89,9 @@ Docs: https://seam.heyquilt.com/docs
|
|
|
89
89
|
seam org [new <slug> | show <org> | add <org> <member> [--role r] | remove <org> <member>] orgs that own quilts
|
|
90
90
|
seam app [list [--verified]] | new <handle> --name <n> [--org <org>] | show|edit|remove <handle> apps: any tool that connects to Seam, with the permissions and events it asks for
|
|
91
91
|
seam app key new|list <handle> | key remove <handle> <id> an app's private keys (the private half shown once; up to ten live)
|
|
92
|
+
seam app install <handle> [--org <org>] [--repos all|a,b] put an app on your account or an org you run, on all repos or chosen ones
|
|
93
|
+
seam app installs [--org <org>] | repos <installation> all|a,b | accept|pause|resume|uninstall <installation> the apps installed there
|
|
94
|
+
seam app request <handle> --org <org> [--repos a,b] [-m <why>] | requests --org <org> [--all] | approve|decline <request> --org <org> ask an org's admins for an app; they decide
|
|
92
95
|
seam app manager add|remove <handle> <member or email> people who edit an app without being its org's owners
|
|
93
96
|
seam org domain add|check|remove <org> <domain> verify an org by a TXT record at _seam-verify.<domain>
|
|
94
97
|
seam org log <org> [-n <count>] [--before <id>] what happened in an org: members, roles, teams, quilts (owners and admins)
|
package/lib/quilts/cli.js
CHANGED
|
@@ -11,7 +11,7 @@ import { startDaemon, askDaemon } from './daemon.js'
|
|
|
11
11
|
import { rebuild as rebuildBlock, conflictStyle } from './block.js'
|
|
12
12
|
import { describeRebuild, describeOpened } from './describe.js'
|
|
13
13
|
import { findBlock, checkout, status as blockStatus, commitFolder, amendFolder, syncTo, localDiff, saveBlock, pull, toLineTip, restore, reset, clean, localChanges, bytesOf, livePatch } from './block.js'
|
|
14
|
-
import { describeLog, describeShow, describeDiff, describeBlame, describeStatus, describeMerge, describeWrite, describeSquare, describeSquareStatus, describeEvents, describeTag, describeRelease, describeImport, describeImportRecord, describeRestore, describeReset, describeClean, describeLive, describeClaims, describeHandoff, describeFinished, describeResolutions, describeLiveSet, describeLiveJoin, describeMergeBase, describeStack, describeStackDiff, describeGrep, describeBisect, describeCheck, describeReviews, describeInterdiff, describeReviewed, describeSquareCheck, describePolicy, describeKeys, describeTokens, describeNewToken, describeBlock, describeBlocks, describeProtections, describeTeams, describeAccess, describeRedacted, describeRedactions, describeMetrics, describeSquarePolicy, describePolicyVersions, describeOrg, describeOrgs, describeOrgLog, describeOrgDomain, describeApp, describeApps, describeAppKey, describeOrgTeams, describeCheckRuns, describeRerun, describeAncestor, describeContains, describePipeline, describeWatches, describeSearch, describePublicReads } from './describe.js'
|
|
14
|
+
import { describeLog, describeShow, describeDiff, describeBlame, describeStatus, describeMerge, describeWrite, describeSquare, describeSquareStatus, describeEvents, describeTag, describeRelease, describeImport, describeImportRecord, describeRestore, describeReset, describeClean, describeLive, describeClaims, describeHandoff, describeFinished, describeResolutions, describeLiveSet, describeLiveJoin, describeMergeBase, describeStack, describeStackDiff, describeGrep, describeBisect, describeCheck, describeReviews, describeInterdiff, describeReviewed, describeSquareCheck, describePolicy, describeKeys, describeTokens, describeNewToken, describeBlock, describeBlocks, describeProtections, describeTeams, describeAccess, describeRedacted, describeRedactions, describeMetrics, describeSquarePolicy, describePolicyVersions, describeOrg, describeOrgs, describeOrgLog, describeOrgDomain, describeApp, describeApps, describeAppKey, describeInstall, describeInstalls, describeRequest, describeRequests, describeOrgTeams, describeCheckRuns, describeRerun, describeAncestor, describeContains, describePipeline, describeWatches, describeSearch, describePublicReads } from './describe.js'
|
|
15
15
|
import { verifyQuilt, describeVerify } from './attest.js'
|
|
16
16
|
import { confirmWithLocalKey } from './linepolicy.js'
|
|
17
17
|
import { describeAgentToken, describeAgentTokens } from './agent-tokens.js'
|
|
@@ -83,7 +83,7 @@ export function agentTokenExtras (flags) {
|
|
|
83
83
|
return out
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
const VALUE_FLAGS = new Set(['--name', '--org', '--description', '--homepage', '--callback', '--setup', '--webhook', '--events', '--perm', '--authors', '--debounce', '-m', '--installation', '--quilts', '--message', '-n', '--max-count', '--into', '--onto', '--on-conflict', '--quilt', '--square', '--dir', '--line', '--task', '--level', '--title', '--slug', '--format', '--expect-tip', '--side', '--file', '--batch', '--to', '--note', '--after', '--kinds', '--webhook', '--secret', '--branch', '--from', '-S', '--run', '--marks', '--patch', '--on', '--path', '--checks', '--name', '--public-key', '--interval', '--credential', '--as', '--runners', '--run-key', '--state', '--tier', '--tiers', '--tests', '--ci-config', '--commit', '--check', '--log-url', '--at', '--human-only', '--keys', '--reason', '--without', '--allow', '--rules', '--org', '--role', '--agent', '--paths', '--squares', '--hours', '--pre-merge-checks', '--by', '--mode', '--machine', '--add', '--remove', '--exclude', '--max-fetch-bytes', '--expires', '--out', '--auto-combine', '--needs-stack', '--monotonic-stack', '--migrations-in-order', '--rule', '--bisect-width', '--classes', '--min-lines', '-L', '--ignore-rev', '--reverse', '--grep', '-G', '--author', '--on-behalf-of', '--since', '--until', '--group-by', '--cursor', '-U', '--unified', '--renames', '--config', '--only', '--listen', '--idle-exit', '--wait', '--days', '--with', '--stack', '--scope', '--suggest', '--to-line', '--approval-survives', '--stack-defaults', '--stack-keys', '--lfs-url', '--lfs-threshold', '--offset', '--length', '--rate', '--before'])
|
|
86
|
+
const VALUE_FLAGS = new Set(['--repos', '--name', '--org', '--description', '--homepage', '--callback', '--setup', '--webhook', '--events', '--perm', '--authors', '--debounce', '-m', '--installation', '--quilts', '--message', '-n', '--max-count', '--into', '--onto', '--on-conflict', '--quilt', '--square', '--dir', '--line', '--task', '--level', '--title', '--slug', '--format', '--expect-tip', '--side', '--file', '--batch', '--to', '--note', '--after', '--kinds', '--webhook', '--secret', '--branch', '--from', '-S', '--run', '--marks', '--patch', '--on', '--path', '--checks', '--name', '--public-key', '--interval', '--credential', '--as', '--runners', '--run-key', '--state', '--tier', '--tiers', '--tests', '--ci-config', '--commit', '--check', '--log-url', '--at', '--human-only', '--keys', '--reason', '--without', '--allow', '--rules', '--org', '--role', '--agent', '--paths', '--squares', '--hours', '--pre-merge-checks', '--by', '--mode', '--machine', '--add', '--remove', '--exclude', '--max-fetch-bytes', '--expires', '--out', '--auto-combine', '--needs-stack', '--monotonic-stack', '--migrations-in-order', '--rule', '--bisect-width', '--classes', '--min-lines', '-L', '--ignore-rev', '--reverse', '--grep', '-G', '--author', '--on-behalf-of', '--since', '--until', '--group-by', '--cursor', '-U', '--unified', '--renames', '--config', '--only', '--listen', '--idle-exit', '--wait', '--days', '--with', '--stack', '--scope', '--suggest', '--to-line', '--approval-survives', '--stack-defaults', '--stack-keys', '--lfs-url', '--lfs-threshold', '--offset', '--length', '--rate', '--before'])
|
|
87
87
|
|
|
88
88
|
export function parse (argv) {
|
|
89
89
|
const pos = []; const flags = {}; const paths = []
|
|
@@ -635,6 +635,26 @@ export async function runSeamCommand (cmd, argv, { cwd = process.cwd(), token, o
|
|
|
635
635
|
const r = act === 'new' ? await client.addAppKey(h) : act === 'list' ? await client.appKeys(h) : await client.removeAppKey(h, id)
|
|
636
636
|
return print(r, describeAppKey(r))
|
|
637
637
|
}
|
|
638
|
+
if (['request', 'requests', 'approve', 'decline'].includes(sub)) {
|
|
639
|
+
// seam app request <handle> --org <org> [--repos a,b] [-m <why>] | requests --org <org> [--all] | approve|decline <request id> --org <org>
|
|
640
|
+
const org = typeof flags['--org'] === 'string' ? flags['--org'] : null
|
|
641
|
+
if (!org || (sub !== 'requests' && !pos[1])) throw new Error('seam app request <handle> --org <org> [--repos a,b] [-m <why>] | requests --org <org> [--all] | approve|decline <request> --org <org>')
|
|
642
|
+
if (sub === 'requests') { const r = await client.orgRequests(org, { all: !!flags['--all'] }); return print(r, describeRequests(r)) }
|
|
643
|
+
const r = sub === 'request' ? await client.requestApp(pos[1], { org, repos: typeof flags['--repos'] === 'string' && flags['--repos'] !== 'all' ? flags['--repos'].split(',').map((x) => x.trim()).filter(Boolean) : 'all', ...(typeof flags['-m'] === 'string' ? { note: flags['-m'] } : {}) })
|
|
644
|
+
: await client.decideRequest(org, pos[1], sub)
|
|
645
|
+
return print(r, describeRequest(r))
|
|
646
|
+
}
|
|
647
|
+
if (['install', 'installs', 'repos', 'accept', 'pause', 'resume', 'uninstall'].includes(sub)) {
|
|
648
|
+
// seam app install <handle> [--org <org>] [--repos all|a,b] | installs [--org <org>] | repos <install id> all|a,b | pause|resume|uninstall <install id>
|
|
649
|
+
const repos = (v) => v == null || v === true || v === 'all' ? 'all' : String(v).split(',').map((x) => x.trim()).filter(Boolean)
|
|
650
|
+
const str = (f) => typeof flags[f] === 'string' ? flags[f] : undefined
|
|
651
|
+
if (sub === 'installs') { const r = str('--org') ? await client.orgInstallations(str('--org')) : await client.myInstallations(); return print(r, describeInstalls(r)) }
|
|
652
|
+
if (!pos[1] || (sub === 'repos' && !pos[2])) throw new Error('seam app install <handle> [--org <org>] [--repos all|<quilt>,<quilt>] | installs [--org <org>] | repos <installation> all|<quilt>,… | pause|resume|uninstall <installation>')
|
|
653
|
+
const r = sub === 'install' ? await client.installApp(pos[1], { ...(str('--org') ? { org: str('--org') } : {}), repos: repos(flags['--repos']) })
|
|
654
|
+
: sub === 'repos' ? await client.editInstallation(pos[1], { repos: repos(pos[2]) })
|
|
655
|
+
: sub === 'accept' ? await client.acceptInstallation(pos[1]) : sub === 'pause' ? await client.pauseInstallation(pos[1]) : sub === 'resume' ? await client.resumeInstallation(pos[1]) : await client.deleteInstallation(pos[1])
|
|
656
|
+
return print(r, describeInstall(r))
|
|
657
|
+
}
|
|
638
658
|
if (sub === 'manager') {
|
|
639
659
|
// seam app manager add|remove <handle> <person or email>
|
|
640
660
|
const [, act, h, who] = pos
|
|
@@ -642,8 +662,10 @@ export async function runSeamCommand (cmd, argv, { cwd = process.cwd(), token, o
|
|
|
642
662
|
const r = act === 'add' ? await client.addAppManager(h, who) : await client.removeAppManager(h, who)
|
|
643
663
|
return print(r, describeApp(r))
|
|
644
664
|
}
|
|
645
|
-
const usage = 'seam app [list [--verified]] | new <handle> --name <name> [--org <org>] | show <handle> | edit <handle> | remove <handle> | key new|list|remove <handle> [id] | manager add|remove <handle> <member
|
|
646
|
-
if (!['new', 'show', 'edit', 'remove'].includes(sub) || !pos[1]) throw new Error(usage)
|
|
665
|
+
const usage = 'seam app [list [--verified]] | new <handle> --name <name> [--org <org>] | show <handle> | edit <handle> | remove <handle> | key new|list|remove <handle> [id] | manager add|remove <handle> <member> | install <handle> [--org <org>] [--repos a,b] | installs [--org <org>] | repos|accept|pause|resume|uninstall <installation> | request <handle> --org <org> | requests --org <org> | approve|decline <request> --org <org> | disable <handle> [--reason <why>] | enable <handle> (Seam staff); new and edit take --name --description --homepage --callback --setup --webhook <url>, --events a,b, --perm contents=read,reviews=write, --public|--private, and edit --new-secret'
|
|
666
|
+
if (!['new', 'show', 'edit', 'remove', 'disable', 'enable'].includes(sub) || !pos[1]) throw new Error(usage)
|
|
667
|
+
if (sub === 'disable') { const r = await client.disableApp(pos[1], typeof flags['--reason'] === 'string' ? flags['--reason'] : undefined); return print(r, describeApp(r)) }
|
|
668
|
+
if (sub === 'enable') { const r = await client.enableApp(pos[1]); return print(r, describeApp(r)) }
|
|
647
669
|
if (sub === 'show') { const r = await client.app(pos[1]); return print(r, describeApp(r)) }
|
|
648
670
|
if (sub === 'remove') { const r = await client.deleteApp(pos[1]); return print(r, describeApp(r)) }
|
|
649
671
|
const b = {}
|
|
@@ -657,6 +679,7 @@ export async function runSeamCommand (cmd, argv, { cwd = process.cwd(), token, o
|
|
|
657
679
|
if (flags['--private']) b.public = false
|
|
658
680
|
if (sub === 'new') { const r = await client.createApp({ handle: pos[1], name: b.name || pos[1], ...(str('--org') ? { org: str('--org') } : {}), ...b }); return print(r, describeApp(r)) }
|
|
659
681
|
if (flags['--new-secret']) b.webhook_secret = true
|
|
682
|
+
if (str('--org') !== undefined) b.org = str('--org')
|
|
660
683
|
const r = await client.editApp(pos[1], b)
|
|
661
684
|
return print(r, describeApp(r))
|
|
662
685
|
}
|
package/lib/quilts/client.js
CHANGED
|
@@ -317,10 +317,24 @@ export function quiltClient ({ api, token, fetch: fetchImpl = globalThis.fetch,
|
|
|
317
317
|
editApp: (h, b) => call('PATCH', `/v1/apps/${enc(h)}`, b),
|
|
318
318
|
addAppManager: (h, member) => call('POST', `/v1/apps/${enc(h)}/managers`, { member }),
|
|
319
319
|
removeAppManager: (h, member) => call('DELETE', `/v1/apps/${enc(h)}/managers/${enc(member)}`),
|
|
320
|
+
installApp: (h, b = {}) => call('POST', `/v1/apps/${enc(h)}/installations`, b),
|
|
321
|
+
requestApp: (h, b) => call('POST', `/v1/apps/${enc(h)}/requests`, b),
|
|
322
|
+
orgRequests: (o, { all } = {}) => call('GET', `/v1/orgs/${enc(o)}/requests${all ? '?all=1' : ''}`),
|
|
323
|
+
decideRequest: (o, id, verdict) => call('POST', `/v1/orgs/${enc(o)}/requests/${enc(id)}/${verdict === 'decline' ? 'decline' : 'approve'}`, {}),
|
|
324
|
+
myInstallations: () => call('GET', '/v1/me/installations'),
|
|
325
|
+
orgInstallations: (o) => call('GET', `/v1/orgs/${enc(o)}/installations`),
|
|
326
|
+
installation: (id) => call('GET', `/v1/installations/${enc(id)}`),
|
|
327
|
+
editInstallation: (id, b) => call('PATCH', `/v1/installations/${enc(id)}`, b),
|
|
328
|
+
acceptInstallation: (id) => call('POST', `/v1/installations/${enc(id)}/accept`, {}),
|
|
329
|
+
pauseInstallation: (id) => call('POST', `/v1/installations/${enc(id)}/pause`, {}),
|
|
330
|
+
resumeInstallation: (id) => call('POST', `/v1/installations/${enc(id)}/resume`, {}),
|
|
331
|
+
deleteInstallation: (id) => call('DELETE', `/v1/installations/${enc(id)}`),
|
|
320
332
|
appKeys: (h) => call('GET', `/v1/apps/${enc(h)}/keys`),
|
|
321
333
|
addAppKey: (h) => call('POST', `/v1/apps/${enc(h)}/keys`, {}),
|
|
322
334
|
removeAppKey: (h, id) => call('DELETE', `/v1/apps/${enc(h)}/keys/${enc(id)}`),
|
|
323
335
|
deleteApp: (h) => call('DELETE', `/v1/apps/${enc(h)}`),
|
|
336
|
+
disableApp: (h, reason) => call('POST', `/v1/apps/${enc(h)}/disable`, reason ? { reason } : {}),
|
|
337
|
+
enableApp: (h) => call('POST', `/v1/apps/${enc(h)}/enable`, {}),
|
|
324
338
|
createOrg: (b) => call('POST', '/v1/orgs', b),
|
|
325
339
|
org: (o) => call('GET', `/v1/orgs/${enc(o)}`),
|
|
326
340
|
addOrgDomain: (o, domain) => call('POST', `/v1/orgs/${enc(o)}/domains`, { domain }),
|
package/lib/quilts/describe.js
CHANGED
|
@@ -511,9 +511,11 @@ export function describeApp (a) {
|
|
|
511
511
|
const perms = Object.entries(a.permissions || {}).filter(([, l]) => l !== 'none').map(([r, l]) => `${r} ${l}`)
|
|
512
512
|
return [
|
|
513
513
|
`${a.handle}: ${a.name}, ${a.public ? 'public' : 'private'}, owned by ${owner}`,
|
|
514
|
+
...(a.disabled ? [` Switched off by Seam${a.disabled.reason ? `: ${a.disabled.reason}` : ''}. It installs nowhere and its installs do nothing until Seam switches it on.`] : []),
|
|
514
515
|
...(a.description ? [` ${a.description}`] : []),
|
|
515
516
|
` May: ${perms.length ? perms.join(', ') : 'nothing yet (every permission is none)'}`,
|
|
516
517
|
` Hears: ${a.events?.length ? a.events.join(', ') : 'no events'}`,
|
|
518
|
+
...(a.installs != null ? [` Installs: ${a.installs}`] : []),
|
|
517
519
|
...['homepage', 'callback_url', 'setup_url', 'webhook_url'].filter((k) => a[k]).map((k) => ` ${k}: ${a[k]}`),
|
|
518
520
|
...(a.managers?.length ? [` Managers: ${a.managers.join(', ')}`] : []),
|
|
519
521
|
...(a.keys ? [` Keys: ${a.keys.length ? a.keys.map((k) => k.id).join(', ') : 'none'}`] : []),
|
|
@@ -528,6 +530,32 @@ export function describeAppKey (k) {
|
|
|
528
530
|
return k.keys.length ? k.keys.map((x) => `${x.id} made ${new Date(x.created_at).toISOString().slice(0, 10)} by ${x.created_by}`).join('\n') : 'No keys.'
|
|
529
531
|
}
|
|
530
532
|
|
|
533
|
+
/** An app installed on an account or an org (19.4): where, on which repos, what it may do. */
|
|
534
|
+
export function describeInstall (i) {
|
|
535
|
+
if (i.removed) return `Removed the installation ${i.id}: the app is off that account.`
|
|
536
|
+
const where = i.target?.kind === 'org' ? `the org ${i.target.slug || i.target.id}` : (i.target?.name || i.target?.id)
|
|
537
|
+
const perms = Object.entries(i.permissions || {}).filter(([, l]) => l !== 'none').map(([r, l]) => `${r} ${l}`)
|
|
538
|
+
return [
|
|
539
|
+
`${i.app?.handle || i.app?.id} on ${where}${i.paused ? ' (paused)' : ''}: installation ${i.id}`,
|
|
540
|
+
` Repos: ${i.repos === 'all' ? 'all, and later ones' : i.repos.join(', ')}`,
|
|
541
|
+
` May: ${perms.length ? perms.join(', ') : 'nothing'}`,
|
|
542
|
+
...(i.pending_permissions ? [` Asks for more, waiting for you to accept (seam app accept ${i.id}): ${Object.entries(i.pending_permissions).map(([r, l]) => `${r} ${l}`).join(', ')}`] : []),
|
|
543
|
+
...(i.unverified ? [' Unverified: the org that makes this app has no verified domain'] : []),
|
|
544
|
+
...(i.disabled ? [' Switched off by Seam: this install does nothing until Seam switches the app on'] : [])
|
|
545
|
+
].join('\n')
|
|
546
|
+
}
|
|
547
|
+
/** A member's request for an app on an org (19.4), and what an admin decided. */
|
|
548
|
+
export function describeRequest (r) {
|
|
549
|
+
const repos = r.repos === 'all' ? 'all repos' : r.repos.join(', ')
|
|
550
|
+
return [
|
|
551
|
+
`Request ${r.id}: ${r.app?.handle || r.app?.id} on ${repos}, asked by ${r.requested_by}: ${r.state}${r.decided_by ? ` by ${r.decided_by}` : r.state === 'pending' ? ' (the org\'s admins approve or decline it)' : ''}`,
|
|
552
|
+
...(r.note ? [` "${r.note}"`] : []),
|
|
553
|
+
...(r.installation ? [` Installed: installation ${r.installation.id}`] : [])
|
|
554
|
+
].join('\n')
|
|
555
|
+
}
|
|
556
|
+
export const describeRequests = (r) => r.requests.length ? r.requests.map(describeRequest).join('\n') : 'No app requests.'
|
|
557
|
+
export const describeInstalls = (r) => r.installations.length ? r.installations.map(describeInstall).join('\n\n') : 'No apps installed.'
|
|
558
|
+
|
|
531
559
|
export const describeApps = (r) => r.apps.length ? r.apps.map((a) => describeApp(a)).join('\n\n') : 'No apps.'
|
|
532
560
|
|
|
533
561
|
export function describeOrgLog (r) {
|
|
@@ -536,7 +564,8 @@ export function describeOrgLog (r) {
|
|
|
536
564
|
if (x.kind === 'created') return `made the org ${d.slug}`
|
|
537
565
|
if (x.kind === 'member') return d.role ? `${d.was ? `made ${d.member} ${d.role === 'admin' || d.role === 'owner' ? 'an' : 'a'} ${d.role} (was ${d.was})` : `added ${d.member} as ${d.role === 'member' ? 'a' : 'an'} ${d.role}`}` : `removed ${d.member} (was ${d.was})`
|
|
538
566
|
if (x.kind === 'team') return d.members?.length ? `set the team ${d.name}: ${d.members.join(', ')}` : `removed the team ${d.name}`
|
|
539
|
-
if (x.kind.startsWith('app_')) return `${{ app_created: 'made', app_changed: 'changed', app_removed: 'removed', app_manager_added: `made ${d.member} a manager of`, app_manager_removed: `took ${d.member} off the managers of`, app_key_added: `made a key ${d.key_id} for`, app_key_removed: `removed the key ${d.key_id} of` }[x.kind] || x.kind}${x.kind.startsWith('app_key') || x.kind.startsWith('app_manager') ? '' : ' the app'} ${d.handle} ${d.handle}${d.fields?.length ? ` (${d.fields.join(', ')})` : ''}`
|
|
567
|
+
if (x.kind.startsWith('app_')) return `${{ app_created: 'made', app_changed: 'changed', app_removed: 'removed', app_manager_added: `made ${d.member} a manager of`, app_manager_removed: `took ${d.member} off the managers of`, app_key_added: `made a key ${d.key_id} for`, app_key_removed: `removed the key ${d.key_id} of`, app_moved_in: `moved in from ${d.from}` }[x.kind] || x.kind}${x.kind.startsWith('app_key') || x.kind.startsWith('app_manager') || x.kind === 'app_moved_in' ? '' : ' the app'} ${d.handle} ${d.handle}${d.fields?.length ? ` (${d.fields.join(', ')})` : ''}`
|
|
568
|
+
if (x.kind === 'app_installed' || x.kind === 'app_uninstalled' || x.kind.startsWith('install_')) return `${{ app_installed: 'installed', app_uninstalled: 'removed', install_requested: 'asked for', install_request_approved: 'approved the request for', install_request_declined: 'declined the request for', install_repos_changed: 'changed the repos of', install_paused: 'paused', install_permissions_accepted: 'accepted new permissions for', install_resumed: 'resumed' }[x.kind] || x.kind} the app ${d.handle}${['app_installed', 'install_repos_changed', 'install_requested'].includes(x.kind) ? ` (${d.repos ? d.repos.join(', ') : 'all repos'})` : ''}`
|
|
540
569
|
if (x.kind.startsWith('domain_')) return `${{ domain_added: 'added', domain_verified: 'verified', domain_lost: 'lost (its record went away)', domain_removed: 'removed' }[x.kind] || x.kind} the domain ${d.domain}`
|
|
541
570
|
if (x.kind === 'quilt_in') return `moved the quilt ${d.slug} in (from ${d.from})`
|
|
542
571
|
if (x.kind === 'quilt_out') return `moved the quilt ${d.slug} out (to ${d.to})`
|
package/lib/quilts/tools.js
CHANGED
|
@@ -12,14 +12,14 @@ import { verifyQuilt, describeVerify } from './attest.js'
|
|
|
12
12
|
import { codecFor, catBytes, grantSealed, describeSeal, startSealedIfNew } from './sealed.js'
|
|
13
13
|
import { confirmWithLocalKey } from './linepolicy.js'
|
|
14
14
|
import { describeAgentToken, describeAgentTokens } from './agent-tokens.js'
|
|
15
|
-
import { eventLine, describeLog, describeShow, describeDiff, describeBlame, describeStatus, describeMerge, describeWrite, describeSquare, describeSquareStatus, describeEvents, describeTag, describeRelease, describeImport, describeImportRecord, describeRestore, describeReset, describeClean, describeLive, describeClaims, describeResolutions, describeLiveSet, describeLiveJoin, describeMergeBase, describeStack, describeStackDiff, describeGrep, describeBisect, describeCheck, describeReviews, describeInterdiff, describeReviewed, describeSquareCheck, describePolicy, describeKeys, describeTokens, describeNewToken, describeProtections, describeTeams, describeAccess, describeRedacted, describeRedactions, describeMetrics, describeSquarePolicy, describePolicyVersions, describeOrg, describeOrgs, describeOrgLog, describeOrgDomain, describeApp, describeApps, describeAppKey, describeOrgTeams, describeCheckRuns, describeRerun, describeHandoff, describeFinished, describeAncestor, describeContains, describePipeline, describeWatches, describeSearch, describePublicReads } from './describe.js'
|
|
15
|
+
import { eventLine, describeLog, describeShow, describeDiff, describeBlame, describeStatus, describeMerge, describeWrite, describeSquare, describeSquareStatus, describeEvents, describeTag, describeRelease, describeImport, describeImportRecord, describeRestore, describeReset, describeClean, describeLive, describeClaims, describeResolutions, describeLiveSet, describeLiveJoin, describeMergeBase, describeStack, describeStackDiff, describeGrep, describeBisect, describeCheck, describeReviews, describeInterdiff, describeReviewed, describeSquareCheck, describePolicy, describeKeys, describeTokens, describeNewToken, describeProtections, describeTeams, describeAccess, describeRedacted, describeRedactions, describeMetrics, describeSquarePolicy, describePolicyVersions, describeOrg, describeOrgs, describeOrgLog, describeOrgDomain, describeApp, describeApps, describeAppKey, describeInstall, describeInstalls, describeRequest, describeRequests, describeOrgTeams, describeCheckRuns, describeRerun, describeHandoff, describeFinished, describeAncestor, describeContains, describePipeline, describeWatches, describeSearch, describePublicReads } from './describe.js'
|
|
16
16
|
import { signWithLocalKey, localKey, makeLocalKey, signingKeyFile } from './signing.js'
|
|
17
17
|
import { startDaemon, askDaemon } from './daemon.js'
|
|
18
18
|
import { rebuild as rebuildBlock, conflictStyle } from './block.js'
|
|
19
19
|
import { describeRebuild, describeOpened } from './describe.js'
|
|
20
20
|
import { status as blockStatus, commitFolder, amendFolder, syncTo, pull, toLineTip, checkout, restore, reset, clean, localChanges, bytesOf, livePatch } from './block.js'
|
|
21
21
|
|
|
22
|
-
export const SEAM_TOOLS = ['seam_quilts', 'seam_open_square', 'seam_squares', 'seam_log', 'seam_show', 'seam_diff', 'seam_blame', 'seam_cat', 'seam_ls', 'seam_commit', 'seam_merge', 'seam_rebase', 'seam_revert', 'seam_cherry_pick', 'seam_resolve', 'seam_square_status', 'seam_square_handoff', 'seam_abandon', 'seam_square_merged', 'seam_reopen', 'seam_fold', 'seam_split', 'seam_events', 'seam_events_webhook', 'seam_line_list', 'seam_line_new', 'seam_line_freeze', 'seam_line_unfreeze', 'seam_line_require', 'seam_reviews', 'seam_review', 'seam_tag_list', 'seam_tag', 'seam_release_list', 'seam_release', 'seam_import_git', 'seam_import_remote', 'seam_github', 'seam_github_import', 'seam_import_status', 'seam_import_authors', 'seam_import_poke', 'seam_import_cutover', 'seam_export_remote', 'seam_export_status', 'seam_restore', 'seam_reset', 'seam_clean', 'seam_live', 'seam_live_join', 'seam_live_set', 'seam_bisect', 'seam_grep', 'seam_search', 'seam_describe', 'seam_merge_base', 'seam_stack', 'seam_migrations_dir', 'seam_claims', 'seam_claim', 'seam_unclaim', 'seam_check', 'seam_resolutions', 'seam_forget_resolution', 'seam_sign', 'seam_keys', 'seam_key_add', 'seam_key_remove', 'seam_token_list', 'seam_token_new', 'seam_token_revoke', 'seam_protections', 'seam_protections_set', 'seam_team_set', 'seam_verify', 'seam_redact', 'seam_redactions', 'seam_seal', 'seam_secret_scanning', 'seam_public', 'seam_sealed', 'seam_policy', 'seam_line_policy_versions', 'seam_orgs', 'seam_org_log', 'seam_org_domain', 'seam_apps', 'seam_app', 'seam_app_key', 'seam_app_manager', 'seam_org_member', 'seam_org_team', 'seam_agent_token_new', 'seam_agent_token_list', 'seam_agent_token_revoke', 'seam_agents_make_lines', 'seam_checks', 'seam_check_rerun', 'seam_reparent', 'seam_archive', 'seam_unarchive', 'seam_hide', 'seam_unhide', 'seam_square_edit', 'seam_share', 'seam_unshare', 'seam_export_tarball', 'seam_claim_request', 'seam_claim_withdraw', 'seam_claim_handoff', 'seam_claim_finish', 'seam_blocks', 'seam_block_open', 'seam_block_touch', 'seam_block_close', 'seam_ancestor', 'seam_contains', 'seam_pipeline', 'seam_watch', 'seam_unwatch', 'seam_absorb', 'seam_interdiff', 'seam_apply_suggestion', 'seam_infra_paths', 'seam_owner_idle_hours', 'seam_public_reads', 'seam_export_archive', 'seam_metrics', 'seam_daemon', 'seam_block_rebuild', 'seam_clone', 'seam_pull', 'seam_member_add']
|
|
22
|
+
export const SEAM_TOOLS = ['seam_quilts', 'seam_open_square', 'seam_squares', 'seam_log', 'seam_show', 'seam_diff', 'seam_blame', 'seam_cat', 'seam_ls', 'seam_commit', 'seam_merge', 'seam_rebase', 'seam_revert', 'seam_cherry_pick', 'seam_resolve', 'seam_square_status', 'seam_square_handoff', 'seam_abandon', 'seam_square_merged', 'seam_reopen', 'seam_fold', 'seam_split', 'seam_events', 'seam_events_webhook', 'seam_line_list', 'seam_line_new', 'seam_line_freeze', 'seam_line_unfreeze', 'seam_line_require', 'seam_reviews', 'seam_review', 'seam_tag_list', 'seam_tag', 'seam_release_list', 'seam_release', 'seam_import_git', 'seam_import_remote', 'seam_github', 'seam_github_import', 'seam_import_status', 'seam_import_authors', 'seam_import_poke', 'seam_import_cutover', 'seam_export_remote', 'seam_export_status', 'seam_restore', 'seam_reset', 'seam_clean', 'seam_live', 'seam_live_join', 'seam_live_set', 'seam_bisect', 'seam_grep', 'seam_search', 'seam_describe', 'seam_merge_base', 'seam_stack', 'seam_migrations_dir', 'seam_claims', 'seam_claim', 'seam_unclaim', 'seam_check', 'seam_resolutions', 'seam_forget_resolution', 'seam_sign', 'seam_keys', 'seam_key_add', 'seam_key_remove', 'seam_token_list', 'seam_token_new', 'seam_token_revoke', 'seam_protections', 'seam_protections_set', 'seam_team_set', 'seam_verify', 'seam_redact', 'seam_redactions', 'seam_seal', 'seam_secret_scanning', 'seam_public', 'seam_sealed', 'seam_policy', 'seam_line_policy_versions', 'seam_orgs', 'seam_org_log', 'seam_org_domain', 'seam_apps', 'seam_app', 'seam_app_key', 'seam_app_manager', 'seam_app_install', 'seam_app_request', 'seam_org_member', 'seam_org_team', 'seam_agent_token_new', 'seam_agent_token_list', 'seam_agent_token_revoke', 'seam_agents_make_lines', 'seam_checks', 'seam_check_rerun', 'seam_reparent', 'seam_archive', 'seam_unarchive', 'seam_hide', 'seam_unhide', 'seam_square_edit', 'seam_share', 'seam_unshare', 'seam_export_tarball', 'seam_claim_request', 'seam_claim_withdraw', 'seam_claim_handoff', 'seam_claim_finish', 'seam_blocks', 'seam_block_open', 'seam_block_touch', 'seam_block_close', 'seam_ancestor', 'seam_contains', 'seam_pipeline', 'seam_watch', 'seam_unwatch', 'seam_absorb', 'seam_interdiff', 'seam_apply_suggestion', 'seam_infra_paths', 'seam_owner_idle_hours', 'seam_public_reads', 'seam_export_archive', 'seam_metrics', 'seam_daemon', 'seam_block_rebuild', 'seam_clone', 'seam_pull', 'seam_member_add']
|
|
23
23
|
|
|
24
24
|
/** What every agent is told about source control, in each MCP's instructions. */
|
|
25
25
|
export const SEAM_GUIDE = 'Quilt source control (quilts): a quilt is a repository on the Quilt server; you work in a square (your own branch and working copy), commit save points in it, and merge it into main, where it becomes a patch. ' +
|
|
@@ -102,8 +102,10 @@ export const SEAM_DESCRIPTIONS = {
|
|
|
102
102
|
seam_orgs: 'Your orgs (who may own quilts besides people), or one org with org: its members by role (owner, admin, member) and its quilts.',
|
|
103
103
|
seam_org_log: 'What happened in an org, newest first: made, members added, removed or given a role, teams set, quilts moved in or out; who did it and when. Its admins and owners. before: a row id, for the page after.',
|
|
104
104
|
seam_apps: 'Lists apps: the ones you change (yours, and your orgs\' where you are admin or owner), or with verified the public apps of verified orgs.',
|
|
105
|
-
seam_app: 'An app (any tool that connects to Seam): new makes one (owned by you, or by org when you are its admin or owner; a webhook secret Seam makes is shown once), show reads it (its public view when it is public and not yours), edit changes the fields given (permissions named change, the rest keep theirs; new_secret makes a new webhook secret), remove deletes it. Permissions are none, read or write for contents, squares, merges, lines, checks, reviews, claims, members and settings.',
|
|
105
|
+
seam_app: 'An app (any tool that connects to Seam): new makes one (owned by you, or by org when you are its admin or owner; a webhook secret Seam makes is shown once), show reads it (its public view when it is public and not yours), edit changes the fields given (permissions named change, the rest keep theirs; new_secret makes a new webhook secret), remove deletes it; disable (with a reason) and enable switch it off or on for everyone, for Seam staff only. Permissions are none, read or write for contents, squares, merges, lines, checks, reviews, claims, members and settings.',
|
|
106
106
|
seam_app_key: 'An app\'s private keys (Ed25519): new makes one and answers its private half (PEM) this once, list gives the public halves, remove ends one. Up to ten live, for rotation. Its owner, managers, or its org\'s admins and owners.',
|
|
107
|
+
seam_app_install: 'Installs an app and manages its installations. install puts the app (handle) on your account, or on org when you are its admin or owner, on repos (quilt ids or slugs of that account) or all of them and later ones, with the permissions the app asks; an app from an org without a verified domain says unverified. list gives the apps on your account, or on org. show, repos (change which repos), accept (take the permissions the app added since: until then the install keeps its old set, listed as pending_permissions), pause, resume and remove take the installation id. Only the person, or the org\'s admins and owners.',
|
|
108
|
+
seam_app_request: 'Install requests on an org: ask (an org member who is not its admin asks for the app handle, on repos or all, with a note), list (the org\'s open requests, or all with all; its admins and owners), approve (installs it with the repos asked) or decline (id). An admin installs with seam_app_install instead.',
|
|
107
109
|
seam_app_manager: 'Adds or removes a manager of an app (a person, by member id or email): managers edit the app and make its keys without being its org\'s owners. Its owner or its org\'s admins and owners.',
|
|
108
110
|
seam_org_domain: 'Verifies an org by a domain it names: add gives the TXT record to put at _seam-verify.<domain>, check looks it up (the org is verified while one of its domains is; a verified domain is looked up again daily), remove drops it. An org\'s admin or owner who is a person.',
|
|
109
111
|
seam_org_team: 'Sets an org\'s team (its members, replaced whole; [] removes it), which the protections of every quilt the org owns name as org_team:<name>. An org\'s admin or owner who is a person.',
|
|
@@ -234,8 +236,10 @@ export const SEAM_INPUTS = {
|
|
|
234
236
|
seam_orgs: { org: z.string().max(100).optional() },
|
|
235
237
|
seam_org_log: { org: z.string().max(100), limit: z.number().int().min(1).max(500).optional(), before: z.string().regex(/^\d{1,19}$/).optional() },
|
|
236
238
|
seam_apps: { verified: z.boolean().optional() },
|
|
237
|
-
seam_app: { action: z.enum(['new', 'show', 'edit', 'remove']), handle: z.string().max(39), name: z.string().max(100).optional(), org: z.string().max(100).optional(), description: z.string().max(2000).optional(), homepage: z.string().max(2000).optional(), callback_url: z.string().max(2000).optional(), setup_url: z.string().max(2000).optional(), webhook_url: z.string().max(2000).optional(), webhook_secret: z.string().min(16).max(200).optional(), new_secret: z.boolean().optional(), events: z.array(z.string().max(50)).max(50).optional(), permissions: z.record(z.string().max(20), z.enum(['none', 'read', 'write'])).optional(), public: z.boolean().optional() },
|
|
239
|
+
seam_app: { action: z.enum(['new', 'show', 'edit', 'remove', 'disable', 'enable']), reason: z.string().max(500).optional().describe('Why, for disable'), handle: z.string().max(39), name: z.string().max(100).optional(), org: z.string().max(100).optional(), description: z.string().max(2000).optional(), homepage: z.string().max(2000).optional(), callback_url: z.string().max(2000).optional(), setup_url: z.string().max(2000).optional(), webhook_url: z.string().max(2000).optional(), webhook_secret: z.string().min(16).max(200).optional(), new_secret: z.boolean().optional(), events: z.array(z.string().max(50)).max(50).optional(), permissions: z.record(z.string().max(20), z.enum(['none', 'read', 'write'])).optional(), public: z.boolean().optional() },
|
|
238
240
|
seam_app_key: { action: z.enum(['new', 'list', 'remove']), handle: z.string().max(39), id: z.string().max(100).optional() },
|
|
241
|
+
seam_app_install: { action: z.enum(['install', 'list', 'show', 'repos', 'accept', 'pause', 'resume', 'remove']), handle: z.string().max(39).optional().describe('The app, for install'), org: z.string().max(100).optional().describe('An org you administer, for install or list'), repos: z.union([z.literal('all'), z.array(z.string().max(200)).min(1).max(500)]).optional().describe('"all" (default) or quilts of the account'), id: z.string().max(100).optional().describe('The installation, for show, repos, pause, resume and remove') },
|
|
242
|
+
seam_app_request: { action: z.enum(['ask', 'list', 'approve', 'decline']), org: z.string().max(100), handle: z.string().max(39).optional().describe('The app, for ask'), repos: z.union([z.literal('all'), z.array(z.string().max(200)).min(1).max(500)]).optional(), note: z.string().max(1000).optional().describe('Why, for ask'), all: z.boolean().optional().describe('For list: decided ones too'), id: z.string().max(100).optional().describe('The request, for approve and decline') },
|
|
239
243
|
seam_app_manager: { action: z.enum(['add', 'remove']), handle: z.string().max(39), member: z.string().max(200) },
|
|
240
244
|
seam_org_domain: { org: z.string().max(100), action: z.enum(['add', 'check', 'remove']), domain: z.string().max(253) },
|
|
241
245
|
seam_org_team: { org: z.string().max(100), name: z.string().max(63), members: z.array(z.string().max(200)).max(1000).describe('member ids (person:… or agent:…), every one in the org; [] removes the team') },
|
|
@@ -639,6 +643,9 @@ export async function runSeamTool (name, args, { client, found = null, hosted =
|
|
|
639
643
|
case 'seam_app': {
|
|
640
644
|
if (args.action === 'show') return describeApp(await client.app(args.handle))
|
|
641
645
|
if (args.action === 'remove') return describeApp(await client.deleteApp(args.handle))
|
|
646
|
+
if (args.action === 'disable') return describeApp(await client.disableApp(args.handle, args.reason))
|
|
647
|
+
if (args.action === 'enable') return describeApp(await client.enableApp(args.handle))
|
|
648
|
+
delete args.reason
|
|
642
649
|
const { action, handle, new_secret: fresh, ...b } = args
|
|
643
650
|
if (action === 'new') return describeApp(await client.createApp({ handle, name: b.name || handle, ...b }))
|
|
644
651
|
return describeApp(await client.editApp(handle, { ...b, ...(fresh ? { webhook_secret: true } : {}) }))
|
|
@@ -647,6 +654,21 @@ export async function runSeamTool (name, args, { client, found = null, hosted =
|
|
|
647
654
|
if (args.action === 'remove' && !args.id) throw new Error('give the key id to remove')
|
|
648
655
|
return describeAppKey(await (args.action === 'new' ? client.addAppKey(args.handle) : args.action === 'list' ? client.appKeys(args.handle) : client.removeAppKey(args.handle, args.id)))
|
|
649
656
|
}
|
|
657
|
+
case 'seam_app_install': {
|
|
658
|
+
const { action, handle, org, repos, id } = args
|
|
659
|
+
if (action === 'list') return describeInstalls(await (org ? client.orgInstallations(org) : client.myInstallations()))
|
|
660
|
+
if (action === 'install') { if (!handle) throw new Error('give the app handle to install'); return describeInstall(await client.installApp(handle, { ...(org ? { org } : {}), repos: repos || 'all' })) }
|
|
661
|
+
if (!id) throw new Error('give the installation id')
|
|
662
|
+
if (action === 'repos') { if (!repos) throw new Error('give repos: "all" or quilts'); return describeInstall(await client.editInstallation(id, { repos })) }
|
|
663
|
+
return describeInstall(await (action === 'show' ? client.installation(id) : action === 'accept' ? client.acceptInstallation(id) : action === 'pause' ? client.pauseInstallation(id) : action === 'resume' ? client.resumeInstallation(id) : client.deleteInstallation(id)))
|
|
664
|
+
}
|
|
665
|
+
case 'seam_app_request': {
|
|
666
|
+
const { action, org, handle, repos, note, all, id } = args
|
|
667
|
+
if (action === 'list') return describeRequests(await client.orgRequests(org, { all: !!all }))
|
|
668
|
+
if (action === 'ask') { if (!handle) throw new Error('give the app handle to ask for'); return describeRequest(await client.requestApp(handle, { org, repos: repos || 'all', ...(note ? { note } : {}) })) }
|
|
669
|
+
if (!id) throw new Error('give the request id')
|
|
670
|
+
return describeRequest(await client.decideRequest(org, id, action))
|
|
671
|
+
}
|
|
650
672
|
case 'seam_app_manager': return describeApp(await (args.action === 'add' ? client.addAppManager(args.handle, args.member) : client.removeAppManager(args.handle, args.member)))
|
|
651
673
|
case 'seam_org_domain': return describeOrgDomain(await (args.action === 'add' ? client.addOrgDomain(args.org, args.domain) : args.action === 'check' ? client.checkOrgDomain(args.org, args.domain) : client.removeOrgDomain(args.org, args.domain)))
|
|
652
674
|
case 'seam_org_team': return describeOrgTeams(await client.setOrgTeam(args.org, args.name, args.members))
|
package/package.json
CHANGED