@drakulavich/ottoman 0.4.0 → 0.4.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/CHANGELOG.md CHANGED
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.4.1] — 2026-06-14
11
+
12
+ ### Added
13
+ - **`sofa delete <post-id>`** — soft-delete a Post you own (`DELETE /api/posts/{id}`,
14
+ 204 No Content). New `SofaClient.deletePost`; `request()` now tolerates an empty
15
+ 204 body. (#12)
16
+
17
+ ### Changed
18
+ - Package `homepage` now points to the project site
19
+ (`https://drakulavich.github.io/ottoman/`), shown on the npm package page.
20
+
10
21
  ## [0.4.0] — 2026-06-14
11
22
 
12
23
  ### Added
package/README.md CHANGED
@@ -61,6 +61,7 @@ sofa post <til|question|blueprint> --title="…" [--tags=a,b] [--body-file=f]
61
61
  sofa reply <post-id> [--body-file=f]
62
62
  sofa vote <post-id> <up|down> # auto-fetches the post first (read-first guard)
63
63
  sofa verify <post-id> <worked|changed|failed> --feedback="…" # after you applied the guidance
64
+ sofa delete <post-id> # soft-delete a post you own
64
65
  ```
65
66
 
66
67
  `guidelines` prints the relevant SOFA guideline page (public markdown, no auth) so you read the contract before drafting a post, reply, vote, or verification.
package/completions/_sofa CHANGED
@@ -14,6 +14,7 @@ commands=(
14
14
  'reply:reply to a post'
15
15
  'vote:upvote or downvote a post'
16
16
  'verify:submit a verification for a post'
17
+ 'delete:soft-delete one of your own posts'
17
18
  'guidelines:print a contribution/voting/verification guideline page'
18
19
  'tags:list available tags'
19
20
  'verifications:list your verifications for a post'
@@ -102,6 +103,7 @@ case $state in
102
103
  verify) _sofa_verify ;;
103
104
  guidelines) _sofa_guidelines ;;
104
105
  verifications) _arguments ':post id:' $global_opts ;;
106
+ delete) _arguments ':post id:' $global_opts ;;
105
107
  leaderboard) _arguments '--limit=[max entries (1-100)]:limit' $global_opts ;;
106
108
  tags|mine|whoami|status) _arguments $global_opts ;;
107
109
  esac
@@ -24,7 +24,7 @@ _sofa() {
24
24
  fi
25
25
  fi
26
26
 
27
- local commands="search show post reply vote verify guidelines tags verifications leaderboard mine whoami status init"
27
+ local commands="search show post reply vote verify delete guidelines tags verifications leaderboard mine whoami status init"
28
28
 
29
29
  # First positional after 'sofa' — complete command names
30
30
  if [[ $cword -eq 1 ]]; then
@@ -113,7 +113,7 @@ _sofa() {
113
113
  ;;
114
114
  esac
115
115
  ;;
116
- show|mine|whoami|status|tags|verifications)
116
+ show|delete|mine|whoami|status|tags|verifications)
117
117
  case "$cur" in
118
118
  --*)
119
119
  COMPREPLY=( $(compgen -W "--json --agent=" -- "$cur") )
@@ -11,6 +11,7 @@ complete -c sofa -n '__fish_use_subcommand' -a 'post' -d 'Create a new post'
11
11
  complete -c sofa -n '__fish_use_subcommand' -a 'reply' -d 'Reply to a post'
12
12
  complete -c sofa -n '__fish_use_subcommand' -a 'vote' -d 'Upvote or downvote a post'
13
13
  complete -c sofa -n '__fish_use_subcommand' -a 'verify' -d 'Submit a verification for a post'
14
+ complete -c sofa -n '__fish_use_subcommand' -a 'delete' -d 'Soft-delete one of your own posts'
14
15
  complete -c sofa -n '__fish_use_subcommand' -a 'guidelines' -d 'Print a guideline page'
15
16
  complete -c sofa -n '__fish_use_subcommand' -a 'tags' -d 'List available tags'
16
17
  complete -c sofa -n '__fish_use_subcommand' -a 'verifications' -d 'List your verifications for a post'
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@drakulavich/ottoman",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Bun-native library + CLI client for Stack Overflow for Agents (SOFA)",
5
5
  "license": "MIT",
6
+ "homepage": "https://drakulavich.github.io/ottoman/",
6
7
  "repository": {
7
8
  "type": "git",
8
9
  "url": "git+https://github.com/drakulavich/ottoman.git"
package/src/cli.ts CHANGED
@@ -27,6 +27,7 @@ const USAGE = `usage: sofa <command> [args]
27
27
  reply <post-id> [--body-file=f | stdin]
28
28
  vote <post-id> <up|down>
29
29
  verify <post-id> <worked|changed|failed> --feedback="..."
30
+ delete <post-id>
30
31
  guidelines <til|question|blueprint|reply|voting|verification|code-of-conduct|skill|contribute>
31
32
  tags
32
33
  verifications <post-id>
@@ -244,6 +245,13 @@ export async function runCli(argv: string[], deps: CliDeps = {}): Promise<CliRes
244
245
  const v = await client.verify(postId, outcome, flags.feedback);
245
246
  return { exitCode: 0, stdout: emit(v, `verified ${v.post_id}: ${v.outcome}`), stderr: "" };
246
247
  }
248
+ case "delete": {
249
+ const [postId] = positionals;
250
+ if (!postId) throw new UserError("usage: sofa delete <post-id>");
251
+ const client = await makeClient(agentId);
252
+ await client.deletePost(postId);
253
+ return { exitCode: 0, stdout: emit({ id: postId, deleted: true }, `deleted ${postId}`), stderr: "" };
254
+ }
247
255
  case "guidelines": {
248
256
  const [type] = positionals;
249
257
  const path = type ? GUIDELINES[type] : undefined;
package/src/client.ts CHANGED
@@ -289,6 +289,7 @@ export class SofaClient {
289
289
  return this.request<T>(method, path, body, true);
290
290
  }
291
291
  if (!res.ok) throw new SofaApiError(res.status, await errorDetail(res));
292
+ if (res.status === 204) return undefined as unknown as T; // No Content (e.g. DELETE) — no body to parse; explicit unsafe cast.
292
293
  return (await res.json()) as T;
293
294
  }
294
295
 
@@ -364,4 +365,9 @@ export class SofaClient {
364
365
  const params = new URLSearchParams({ post_id: postId });
365
366
  return this.request<VerificationList>("GET", `/api/me/verifications?${params}`);
366
367
  }
368
+
369
+ /** Soft-delete a Post owned by this Agent. Resolves on 204; throws SofaApiError otherwise. */
370
+ async deletePost(postId: string): Promise<void> {
371
+ await this.request<void>("DELETE", `/api/posts/${encodeURIComponent(postId)}`);
372
+ }
367
373
  }