@oneport-dev/cli 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Logging Studio
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # @oneport-dev/cli
2
+
3
+ Oneport from the terminal — feedback, roadmap & changelog for teams (and agents)
4
+ that ship. Built to be equally good for humans (interactive, guided) and AI
5
+ agents (scriptable, non-interactive, JSON-first).
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm install -g @oneport-dev/cli
11
+ # or run without installing
12
+ npx @oneport-dev/cli login
13
+ ```
14
+
15
+ ## Quick start
16
+
17
+ ```sh
18
+ oneport login # paste your API key, then pick a workspace
19
+ oneport posts list # any command prompts you to log in if you aren't
20
+ oneport use <workspace> # switch the active workspace anytime
21
+ ```
22
+
23
+ Get an API key from the dashboard (**Settings → API keys**, the *Agents* page).
24
+ Any command that needs auth will prompt you to log in first when run
25
+ interactively, or exit with a clear error when run in a script.
26
+
27
+ ## Auth & workspaces
28
+
29
+ | Command | What it does |
30
+ | --- | --- |
31
+ | `oneport login [--api-key <k>]` | Store an API key; pick a workspace |
32
+ | `oneport logout` | Clear stored credentials |
33
+ | `oneport whoami` | Show the current identity, workspace, and API URL |
34
+ | `oneport workspace list` | List the workspaces your key can access |
35
+ | `oneport use <slug>` | Switch the active workspace (alias of `workspace select`) |
36
+
37
+ ## Commands
38
+
39
+ ```
40
+ posts list | get | create | update | search | merge | unmerge
41
+ | comment | comments | vote | unvote
42
+ boards list | create
43
+ roadmap
44
+ changelog list | create | update
45
+ ship <postId> --title --content # mark shipped + publish a changelog
46
+ webhooks list | create | delete
47
+ domain get | set | remove
48
+ settings get | set | logo set|remove
49
+ context # brand voice + style exemplars (for agents)
50
+ api <METHOD> <path> # raw authenticated request — 100% coverage
51
+ ```
52
+
53
+ Run `oneport <command> --help` for flags. Example raw call (the `{slug}` is
54
+ filled from your active workspace):
55
+
56
+ ```sh
57
+ oneport api GET '/v1/workspaces/{slug}/posts' --query 'sort=top'
58
+ oneport api POST '/v1/workspaces/{slug}/posts' \
59
+ --data '{"boardSlug":"features","title":"Hi","content":"from the API"}'
60
+ ```
61
+
62
+ ## For AI agents
63
+
64
+ The CLI is designed to be driven non-interactively:
65
+
66
+ - **Auth from the environment** — set `ONEPORT_API_KEY` (and optionally
67
+ `ONEPORT_WORKSPACE`); no `login` step required.
68
+ - **`--json`** prints raw API JSON to **stdout**. All status/progress/prompts go
69
+ to **stderr**, so `oneport posts list --json | jq` is always clean.
70
+ - **Never blocks** — when not a TTY (or with `--no-input`, or `CI=true`) the CLI
71
+ fails fast with an actionable message instead of prompting.
72
+ - **Stable exit codes**: `0` ok · `1` runtime error · `2` usage · `3` auth
73
+ required · `4` not found.
74
+
75
+ ```sh
76
+ export ONEPORT_API_KEY=sk_...
77
+ export ONEPORT_WORKSPACE=acme
78
+ oneport posts list --json | jq '.[].title'
79
+ oneport context --json # fetch brand voice before drafting a changelog
80
+ ```
81
+
82
+ ## Configuration
83
+
84
+ Resolution order: **flag → environment → config file → prompt** (prompt only
85
+ when interactive).
86
+
87
+ | Setting | Flag | Env | Config key |
88
+ | --- | --- | --- | --- |
89
+ | API key | `oneport login --api-key` | `ONEPORT_API_KEY` | `apiKey` |
90
+ | Workspace | `--workspace`, `-w` | `ONEPORT_WORKSPACE` | `workspace` |
91
+ | API URL | `--api-url` | `ONEPORT_URL` (`ONEPORT_API_URL` also works) | `apiUrl` |
92
+
93
+ Credentials are stored at `~/.config/oneport/config.json` (mode `0600`; honors
94
+ `$XDG_CONFIG_HOME`, override with `ONEPORT_CONFIG_DIR`). Color honors
95
+ `NO_COLOR` and is disabled when output isn't a TTY.
96
+
97
+ ## License
98
+
99
+ MIT
@@ -0,0 +1,102 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/format.ts
8
+ function formatPosts(items) {
9
+ if (!items.length) return "No posts.";
10
+ return items.map((p) => {
11
+ const status = p.status ? `[${p.status.slug}]` : "[\u2014]";
12
+ const flags = p.verified === false ? " (unverified)" : "";
13
+ return `\u25B2 ${String(p.voteCount).padStart(3)} ${status.padEnd(14)} ${p.title}${flags} ${p.id}`;
14
+ }).join("\n");
15
+ }
16
+ function formatPost(p) {
17
+ const status = p.status ? p.status.slug : "\u2014";
18
+ const lines = [
19
+ p.title,
20
+ `${p.id} status: ${status} votes: ${p.voteCount} comments: ${p.commentCount ?? 0}`
21
+ ];
22
+ if (p.mergedInto) {
23
+ lines.push(`merged into: ${p.mergedInto.title} (${p.mergedInto.id})`);
24
+ }
25
+ lines.push("", p.content);
26
+ return lines.join("\n");
27
+ }
28
+ function formatRoadmap(columns) {
29
+ if (!columns.length) return "Roadmap is empty.";
30
+ return columns.map((col) => {
31
+ const items = col.items.length ? col.items.map((i) => ` \u25B2 ${i.voteCount} ${i.title}`).join("\n") : " \u2014 empty \u2014";
32
+ return `[${col.status.slug}]
33
+ ${items}`;
34
+ }).join("\n\n");
35
+ }
36
+ function formatChangelogs(items) {
37
+ if (!items.length) return "No changelog entries.";
38
+ return items.map((e) => {
39
+ const state = e.publishedAt ? e.publishedAt.slice(0, 10) : "draft";
40
+ return `${state.padEnd(12)} ${e.title} ${e.id}`;
41
+ }).join("\n");
42
+ }
43
+ function formatBoards(items) {
44
+ if (!items.length) return "No boards.";
45
+ return items.map(
46
+ (b) => `${b.slug.padEnd(20)} ${b.name}${b.isPrivate ? " (private)" : ""}`
47
+ ).join("\n");
48
+ }
49
+ function formatWorkspaces(items, current) {
50
+ if (!items.length) return "No workspaces.";
51
+ return items.map((w) => {
52
+ const marker = w.slug === current ? "*" : " ";
53
+ return `${marker} ${w.slug.padEnd(20)} ${w.name} (${w.role})`;
54
+ }).join("\n");
55
+ }
56
+ function formatComments(items) {
57
+ if (!items.length) return "No comments.";
58
+ return items.map((cm) => {
59
+ const who = cm.isTeamMember ? "team" : "user";
60
+ const when = cm.createdAt ? cm.createdAt.slice(0, 10) : "";
61
+ return `[${who}] ${when} ${cm.content} ${cm.id}`;
62
+ }).join("\n");
63
+ }
64
+ function formatWebhooks(items) {
65
+ if (!items.length) return "No webhooks.";
66
+ return items.map(
67
+ (w) => `${w.disabled ? "\u2717" : "\u2713"} ${w.url} [${w.events.join(", ")}] ${w.id}`
68
+ ).join("\n");
69
+ }
70
+ function formatValue(v) {
71
+ if (v === null || v === void 0) return "\u2014";
72
+ if (typeof v === "object") return JSON.stringify(v);
73
+ return String(v);
74
+ }
75
+ function formatRecord(obj) {
76
+ const entries = Object.entries(obj);
77
+ if (!entries.length) return "(empty)";
78
+ const width = Math.max(...entries.map(([k]) => k.length));
79
+ return entries.map(([k, v]) => `${k.padEnd(width)} ${formatValue(v)}`).join("\n");
80
+ }
81
+ function formatWhoami(info) {
82
+ return formatRecord({
83
+ user: info.user?.email ?? info.user?.name ?? "(unknown)",
84
+ workspace: info.workspace ?? "(none selected)",
85
+ role: info.role ?? "\u2014",
86
+ "api url": info.apiUrl
87
+ });
88
+ }
89
+
90
+ export {
91
+ __export,
92
+ formatPosts,
93
+ formatPost,
94
+ formatRoadmap,
95
+ formatChangelogs,
96
+ formatBoards,
97
+ formatWorkspaces,
98
+ formatComments,
99
+ formatWebhooks,
100
+ formatRecord,
101
+ formatWhoami
102
+ };
@@ -0,0 +1,24 @@
1
+ import {
2
+ formatBoards,
3
+ formatChangelogs,
4
+ formatComments,
5
+ formatPost,
6
+ formatPosts,
7
+ formatRecord,
8
+ formatRoadmap,
9
+ formatWebhooks,
10
+ formatWhoami,
11
+ formatWorkspaces
12
+ } from "./chunk-BH5VTHCM.mjs";
13
+ export {
14
+ formatBoards,
15
+ formatChangelogs,
16
+ formatComments,
17
+ formatPost,
18
+ formatPosts,
19
+ formatRecord,
20
+ formatRoadmap,
21
+ formatWebhooks,
22
+ formatWhoami,
23
+ formatWorkspaces
24
+ };