@heyquilt/seam 0.145.0 → 0.146.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 CHANGED
@@ -109,7 +109,7 @@ Docs: https://seam.heyquilt.com/docs
109
109
  seam quilts new <slug> --sealed a quilt the server never reads: its key lives on members' computers
110
110
  seam quilts sealed on|off --quilt <q> switch a quilt that holds no files yet to sealed or back
111
111
  seam seal [status] | key | grant <member> | rotate [--without <member>] a sealed quilt's key
112
- seam events [--follow|--webhook <url>] What happened to your squares
112
+ seam events [--follow|--webhook <url>|list] What happened to your squares
113
113
  seam export git <dir> Back to git
114
114
  seam mcp The same commands as MCP tools, for your AI tool
115
115
  seam mcp --as-agent [--merge] The same, with the AI tool as an agent of yours, on a token of its own
package/lib/quilts/cli.js CHANGED
@@ -9,7 +9,7 @@ import { quiltClient } from './client.js'
9
9
  import { runChecks, readRunnerConfig, listenForWork } from './runner.js'
10
10
  import { startDaemon, askDaemon } from './daemon.js'
11
11
  import { rebuild as rebuildBlock, conflictStyle } from './block.js'
12
- import { describeRebuild, describeOpened, describeBoth, describePull, describeDeletedQuilt, describeDeletedQuilts, describePersonLog } from './describe.js'
12
+ import { describeRebuild, describeOpened, describeBoth, describePull, describeDeletedQuilt, describeDeletedQuilts, describePersonLog, describeWebhooks } from './describe.js'
13
13
  import { findBlock, checkout, status as blockStatus, commitFolder, amendFolder, syncTo, localDiff, saveBlock, pull, toLineTip, restore, reset, clean, localChanges, bytesOf, livePatch, resolvePulled } from './block.js'
14
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'
@@ -268,9 +268,10 @@ export async function runSeamCommand (cmd, argv, { cwd = process.cwd(), token, o
268
268
  return print(x, `Released ${x.name} at ${where(x)}. Read it as tag:${x.name}.`)
269
269
  }
270
270
  case 'events': {
271
- // seam events [--after n] [--kinds a,b] [--wait seconds | --follow] | --webhook <url> [--add | --remove] [--secret s] [--kinds a,b] | --webhook off
271
+ // seam events [--after n] [--kinds a,b] [--wait seconds | --follow] | --webhook <url> [--add | --remove] [--secret s] [--kinds a,b] | --webhook off | --webhook list
272
272
  const kinds = flags['--kinds'] ? String(flags['--kinds']).split(',') : undefined
273
273
  if (flags['--webhook']) {
274
+ if (flags['--webhook'] === 'list') { const r = await client.webhooks(needQuilt()); return print(r, describeWebhooks(r)) }
274
275
  const off = flags['--webhook'] === 'off'
275
276
  if (!off && flags['--remove']) { const r = await client.subscribe(needQuilt(), { url: flags['--webhook'], remove: true }); return print(r, `Webhook to ${r.url} removed.${r.hooks.length ? ` Still posting to ${r.hooks.map((h) => h.url).join(', ')}.` : ''}`) }
276
277
  const r = await client.subscribe(needQuilt(), off ? { url: null } : { url: flags['--webhook'], secret: flags['--secret'], events: kinds, ...(flags['--add'] ? { add: true } : {}) })
@@ -207,6 +207,7 @@ export function quiltClient ({ api, token, fetch: fetchImpl = globalThis.fetch,
207
207
  revert: (q, b) => call('POST', `${Q(q)}/revert`, b),
208
208
  events: (q, o = {}) => call('GET', `${Q(q)}/events${qs(o)}`),
209
209
  subscribe: (q, b) => call('POST', `${Q(q)}/webhook`, b),
210
+ webhooks: (q) => call('GET', `${Q(q)}/webhook`),
210
211
  show: (q, rev, o = {}) => call('GET', `${Q(q)}/show/${enc(rev)}${qs(o)}`),
211
212
  exportPatches: (q, o = {}) => call('GET', `${Q(q)}/export/git${qs(o)}`),
212
213
  log: (q, o = {}) => call('GET', `${Q(q)}/log${qs(o)}`),
@@ -193,6 +193,13 @@ export function describeMerge (r) {
193
193
  }
194
194
 
195
195
  /** Events as one line each (12's inbox line: kind, who, square, paths, patch, would_conflict). */
196
+ /** Your webhooks in a quilt (GET /webhook): each url with the events it hears; never a secret. */
197
+ export function describeWebhooks (r) {
198
+ const hooks = r.hooks || []
199
+ if (!hooks.length) return 'No webhooks of yours in this quilt.'
200
+ return hooks.map((h) => `${h.url} (${h.events.length > 4 ? `${h.events.length} kinds of event` : h.events.join(', ')})`).join('\n')
201
+ }
202
+
196
203
  export function describeEvents (r) {
197
204
  if (!r.events.length) return `No new events (cursor ${r.after}).`
198
205
  return [...r.events.map(eventLine), `(next: after=${r.after})`].join('\n')
@@ -16,7 +16,7 @@ import { eventLine, describeLog, describeShow, describeDiff, describeBlame, desc
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
- import { describeRebuild, describeOpened, describeBoth, describePull, describeDeletedQuilt, describeDeletedQuilts, describePersonLog } from './describe.js'
19
+ import { describeRebuild, describeOpened, describeBoth, describePull, describeDeletedQuilt, describeDeletedQuilts, describePersonLog, describeWebhooks } from './describe.js'
20
20
  import { status as blockStatus, commitFolder, amendFolder, syncTo, pull, toLineTip, checkout, restore, reset, clean, localChanges, bytesOf, livePatch, resolvePulled } from './block.js'
21
21
 
22
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_export_push', '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', 'seam_quilt_delete', 'seam_quilts_deleted', 'seam_quilt_restore', 'seam_account_log']
@@ -141,7 +141,7 @@ export const SEAM_DESCRIPTIONS = {
141
141
  seam_share: 'Adds a writer to a square you hold, for pairing: up to three people besides you, each able to write to the quilt. An agent with its own account gets its own square instead.',
142
142
  seam_unshare: 'Takes a writer off a square you hold, or takes you off one you were shared on.',
143
143
  seam_events: 'What happened to your work since you last looked: patch.merged (a patch changed files your open square changed, and whether your merge would now conflict), conflict.added (a conflict was kept in your square), square.handoff, square.restacked (your stacked square was moved onto its parent\'s new head or the line, with how many conflicts it now holds), check.requested (you run a check a line names you for: run it on the commit and report with seam_check and its run_key). Pass after (the cursor from the last answer) to get only new ones. Pass wait (seconds, up to 30) to wait for the next one instead of answering at once.',
144
- seam_events_webhook: 'Has the quilt server POST your events to a URL (signed with HMAC-SHA256 over <timestamp>.<body>, retried 3 times), so you are woken instead of polling: url, events (default all), secret (made for you if left out). url: "off" removes them all. add: true keeps your other webhooks (up to 5); remove: true removes the one at url.',
144
+ seam_events_webhook: 'Has the quilt server POST your events to a URL (signed with HMAC-SHA256 over <timestamp>.<body>, retried 3 times), so you are woken instead of polling: url, events (default all), secret (made for you if left out). url: "off" removes them all; url: "list" lists yours (url and events, never the secret). add: true keeps your other webhooks (up to 5); remove: true removes the one at url.',
145
145
  seam_absorb: 'Puts your square\'s uncommitted live work into the commit of the square that last changed each file (amending it and rewriting the commits above it), so a fix to commit 2 of 5 needs no manual rebase. Files no commit of the square changed stay live.',
146
146
  seam_fold: 'Folds a square (square) into another square you hold (into): its work becomes one commit there and the square closes. Live work it shared (seam_live_set) is committed on it first and goes along (commit_live: false refuses with live_work instead). Overlapping changes become conflict markers in the target.',
147
147
  seam_split: 'Splits your square: by paths (groups: [[paths], ...]) or by claim (one group per claim on the square that covers a changed path; the claim and its holder go with it). Each group moves to a new square (same base) as one commit; the largest group, and paths no group names, stay in this square. stacked: true chains the new squares on this one in order instead of opening them side by side.',
@@ -502,6 +502,7 @@ export async function runSeamTool (name, args, { client, found = null, hosted =
502
502
  case 'seam_reopen': { const sq = await client.reopen(needQuilt(), needSquare()); return `Reopened ${describeSquare(sq)}.` }
503
503
  case 'seam_events': return describeEvents(await client.events(needQuilt(), { after: args.after, kinds: args.kinds, ...(args.wait ? { wait: args.wait } : {}) }))
504
504
  case 'seam_events_webhook': {
505
+ if (args.url === 'list') return describeWebhooks(await client.webhooks(needQuilt()))
505
506
  if (args.url === 'off') { await client.subscribe(needQuilt(), { url: null }); return 'Webhooks removed.' }
506
507
  if (args.remove) { const r = await client.subscribe(needQuilt(), { url: args.url, remove: true }); return `Webhook to ${r.url} removed.${r.hooks.length ? ` Still posting to ${r.hooks.map((h) => h.url).join(', ')}.` : ''}` }
507
508
  const r = await client.subscribe(needQuilt(), { url: args.url, events: args.events, secret: args.secret, ...(args.add ? { add: true } : {}) })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heyquilt/seam",
3
- "version": "0.145.0",
3
+ "version": "0.146.0",
4
4
  "description": "seam: Seam's command. Git's verbs for source control that runs on the server, built for many agents and people at once.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",