@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 +21 -0
- package/README.md +99 -0
- package/dist/chunk-BH5VTHCM.mjs +102 -0
- package/dist/format.mjs +24 -0
- package/dist/main.mjs +16768 -0
- package/package.json +41 -0
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
|
+
};
|
package/dist/format.mjs
ADDED
|
@@ -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
|
+
};
|