@opvs-ai/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.
Files changed (43) hide show
  1. package/dist/commands/auth.d.ts +5 -0
  2. package/dist/commands/auth.js +149 -0
  3. package/dist/commands/auth.js.map +1 -0
  4. package/dist/commands/boards.d.ts +5 -0
  5. package/dist/commands/boards.js +69 -0
  6. package/dist/commands/boards.js.map +1 -0
  7. package/dist/commands/comments.d.ts +5 -0
  8. package/dist/commands/comments.js +62 -0
  9. package/dist/commands/comments.js.map +1 -0
  10. package/dist/commands/config.d.ts +5 -0
  11. package/dist/commands/config.js +84 -0
  12. package/dist/commands/config.js.map +1 -0
  13. package/dist/commands/docs.d.ts +5 -0
  14. package/dist/commands/docs.js +145 -0
  15. package/dist/commands/docs.js.map +1 -0
  16. package/dist/commands/session.d.ts +5 -0
  17. package/dist/commands/session.js +43 -0
  18. package/dist/commands/session.js.map +1 -0
  19. package/dist/commands/tasks.d.ts +5 -0
  20. package/dist/commands/tasks.js +139 -0
  21. package/dist/commands/tasks.js.map +1 -0
  22. package/dist/index.d.ts +13 -0
  23. package/dist/index.js +35 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/lib/api.d.ts +27 -0
  26. package/dist/lib/api.js +128 -0
  27. package/dist/lib/api.js.map +1 -0
  28. package/dist/lib/auth-poll.d.ts +15 -0
  29. package/dist/lib/auth-poll.js +46 -0
  30. package/dist/lib/auth-poll.js.map +1 -0
  31. package/dist/lib/config.d.ts +8 -0
  32. package/dist/lib/config.js +39 -0
  33. package/dist/lib/config.js.map +1 -0
  34. package/dist/lib/fingerprint.d.ts +8 -0
  35. package/dist/lib/fingerprint.js +32 -0
  36. package/dist/lib/fingerprint.js.map +1 -0
  37. package/dist/lib/format.d.ts +19 -0
  38. package/dist/lib/format.js +55 -0
  39. package/dist/lib/format.js.map +1 -0
  40. package/dist/types.d.ts +35 -0
  41. package/dist/types.js +9 -0
  42. package/dist/types.js.map +1 -0
  43. package/package.json +36 -0
@@ -0,0 +1,139 @@
1
+ /**
2
+ * opvs tasks — task CRUD + agent convenience endpoints
3
+ */
4
+ import { readFileSync } from "node:fs";
5
+ import { loadConfig } from "../lib/config.js";
6
+ import { createClient } from "../lib/api.js";
7
+ import { buildUrl, printResponse, printJson } from "../lib/format.js";
8
+ export function registerTaskCommands(program) {
9
+ const tasks = program.command("tasks").description("Task management");
10
+ tasks
11
+ .command("list")
12
+ .description("List tasks")
13
+ .option("--board <id>", "Board ID")
14
+ .option("--self", "Only tasks assigned to me")
15
+ .option("--status <status>", "Filter by status (pending, in_progress, review, done)")
16
+ .option("--priority <priority>", "Filter by priority (low, medium, high, critical)")
17
+ .option("--limit <n>", "Max results", "25")
18
+ .action(async (opts) => {
19
+ const cfg = loadConfig();
20
+ try {
21
+ const client = createClient();
22
+ if (opts.self) {
23
+ const params = {};
24
+ if (opts.status)
25
+ params.status = opts.status;
26
+ if (opts.limit)
27
+ params.limit = opts.limit;
28
+ const url = buildUrl("/api/v1/board/agent-api/my-tasks", params, cfg.format);
29
+ const res = await client.get(url);
30
+ await printResponse(res);
31
+ }
32
+ else if (opts.board) {
33
+ const params = {};
34
+ if (opts.status)
35
+ params.status = opts.status;
36
+ if (opts.priority)
37
+ params.priority = opts.priority;
38
+ if (opts.limit)
39
+ params.limit = opts.limit;
40
+ const url = buildUrl(`/api/v1/board/boards/${opts.board}/tasks`, params, cfg.format);
41
+ const res = await client.get(url);
42
+ await printResponse(res);
43
+ }
44
+ else {
45
+ console.error("Specify --board <id> or --self");
46
+ process.exit(1);
47
+ }
48
+ }
49
+ catch (err) {
50
+ const e = err;
51
+ console.error(`Error: ${e.detail || "Failed to list tasks"}`);
52
+ process.exit(1);
53
+ }
54
+ });
55
+ tasks
56
+ .command("get <id>")
57
+ .description("Get task details")
58
+ .action(async (id) => {
59
+ const cfg = loadConfig();
60
+ try {
61
+ const client = createClient();
62
+ const url = buildUrl(`/api/v1/board/tasks/${id}`, undefined, cfg.format);
63
+ const res = await client.get(url);
64
+ await printResponse(res);
65
+ }
66
+ catch (err) {
67
+ const e = err;
68
+ console.error(`Error: ${e.detail || "Failed to get task"}`);
69
+ process.exit(1);
70
+ }
71
+ });
72
+ tasks
73
+ .command("create")
74
+ .description("Create a new task")
75
+ .requiredOption("--board <id>", "Board ID")
76
+ .requiredOption("-t, --title <title>", "Task title")
77
+ .option("-d, --description <desc>", "Task description")
78
+ .option("--priority <priority>", "Priority (low, medium, high, critical)", "medium")
79
+ .option("--assign <agentId>", "Assign to agent ID")
80
+ .action(async (opts) => {
81
+ try {
82
+ const client = createClient();
83
+ const body = {
84
+ title: opts.title,
85
+ priority: opts.priority,
86
+ };
87
+ if (opts.description)
88
+ body.description = opts.description;
89
+ if (opts.assign)
90
+ body.assigned_to = opts.assign;
91
+ const res = await client.post(`/api/v1/board/boards/${opts.board}/tasks`, body);
92
+ const data = await res.json();
93
+ printJson(data);
94
+ }
95
+ catch (err) {
96
+ const e = err;
97
+ console.error(`Error: ${e.detail || "Failed to create task"}`);
98
+ process.exit(1);
99
+ }
100
+ });
101
+ tasks
102
+ .command("update <id>")
103
+ .description("Update a task (status, priority, result)")
104
+ .option("--status <status>", "New status")
105
+ .option("--priority <priority>", "New priority")
106
+ .option("--title <title>", "New title")
107
+ .option("--result <text>", "Result text (inline)")
108
+ .option("--result-file <path>", "Result text from file")
109
+ .action(async (id, opts) => {
110
+ try {
111
+ const client = createClient();
112
+ const body = {};
113
+ if (opts.status)
114
+ body.status = opts.status;
115
+ if (opts.priority)
116
+ body.priority = opts.priority;
117
+ if (opts.title)
118
+ body.title = opts.title;
119
+ if (opts.result)
120
+ body.agent_result_summary = opts.result;
121
+ if (opts.resultFile) {
122
+ body.agent_result_summary = readFileSync(opts.resultFile, "utf-8");
123
+ }
124
+ if (Object.keys(body).length === 0) {
125
+ console.error("Nothing to update. Provide --status, --priority, --title, --result, or --result-file");
126
+ process.exit(1);
127
+ }
128
+ const res = await client.patch(`/api/v1/board/tasks/${id}`, body);
129
+ const data = await res.json();
130
+ printJson(data);
131
+ }
132
+ catch (err) {
133
+ const e = err;
134
+ console.error(`Error: ${e.detail || "Failed to update task"}`);
135
+ process.exit(1);
136
+ }
137
+ });
138
+ }
139
+ //# sourceMappingURL=tasks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tasks.js","sourceRoot":"","sources":["../../src/commands/tasks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @opvs/cli — Terminal access to AgentBoard + AgentDocs for AI coding agents.
4
+ *
5
+ * Usage:
6
+ * opvs auth request -w <slug> -e <email> # Get a PAT token
7
+ * opvs session get --self # Board context
8
+ * opvs tasks list --self --status pending # My pending tasks
9
+ * opvs task update <id> --status review # Complete a task
10
+ * opvs docs search "query" # Search docs
11
+ * opvs init # Print CLAUDE.md snippet
12
+ */
13
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @opvs/cli — Terminal access to AgentBoard + AgentDocs for AI coding agents.
4
+ *
5
+ * Usage:
6
+ * opvs auth request -w <slug> -e <email> # Get a PAT token
7
+ * opvs session get --self # Board context
8
+ * opvs tasks list --self --status pending # My pending tasks
9
+ * opvs task update <id> --status review # Complete a task
10
+ * opvs docs search "query" # Search docs
11
+ * opvs init # Print CLAUDE.md snippet
12
+ */
13
+ import { Command } from "commander";
14
+ import { registerAuthCommands } from "./commands/auth.js";
15
+ import { registerSessionCommands } from "./commands/session.js";
16
+ import { registerBoardCommands } from "./commands/boards.js";
17
+ import { registerTaskCommands } from "./commands/tasks.js";
18
+ import { registerCommentCommands } from "./commands/comments.js";
19
+ import { registerDocsCommands } from "./commands/docs.js";
20
+ import { registerConfigCommands } from "./commands/config.js";
21
+ const program = new Command();
22
+ program
23
+ .name("opvs")
24
+ .description("OPVS CLI — AgentBoard + AgentDocs for AI coding agents")
25
+ .version("0.1.0");
26
+ // Register all command groups
27
+ registerAuthCommands(program);
28
+ registerSessionCommands(program);
29
+ registerBoardCommands(program);
30
+ registerTaskCommands(program);
31
+ registerCommentCommands(program);
32
+ registerDocsCommands(program);
33
+ registerConfigCommands(program);
34
+ program.parse();
35
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,MAAM,CAAC;KACZ,WAAW,CAAC,wDAAwD,CAAC;KACrE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,8BAA8B;AAC9B,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,uBAAuB,CAAC,OAAO,CAAC,CAAC;AACjC,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,uBAAuB,CAAC,OAAO,CAAC,CAAC;AACjC,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAEhC,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * HTTP client wrapper — native fetch with token auth and error handling.
3
+ */
4
+ declare class APIClient {
5
+ private baseUrl;
6
+ private token;
7
+ private brandId;
8
+ constructor();
9
+ private headers;
10
+ private request;
11
+ get(path: string, extraHeaders?: Record<string, string>): Promise<Response>;
12
+ post(path: string, body?: unknown, extraHeaders?: Record<string, string>): Promise<Response>;
13
+ patch(path: string, body?: unknown, extraHeaders?: Record<string, string>): Promise<Response>;
14
+ put(path: string, body?: unknown, extraHeaders?: Record<string, string>): Promise<Response>;
15
+ delete(path: string, extraHeaders?: Record<string, string>): Promise<Response>;
16
+ }
17
+ /**
18
+ * Unauthenticated POST — used for PAT request initiation.
19
+ */
20
+ export declare function apiUnauthPost(baseUrl: string, path: string, body: unknown): Promise<Response>;
21
+ /**
22
+ * Unauthenticated GET with custom auth header — used for poll endpoint.
23
+ */
24
+ export declare function apiUnauthGet(baseUrl: string, path: string, authHeader?: string): Promise<Response>;
25
+ /** Create a new authenticated API client from current config. */
26
+ export declare function createClient(): APIClient;
27
+ export {};
@@ -0,0 +1,128 @@
1
+ /**
2
+ * HTTP client wrapper — native fetch with token auth and error handling.
3
+ */
4
+ import { loadConfig } from "./config.js";
5
+ class APIClient {
6
+ baseUrl;
7
+ token;
8
+ brandId;
9
+ constructor() {
10
+ const config = loadConfig();
11
+ this.baseUrl = config.api_url.replace(/\/$/, "");
12
+ this.token = config.token;
13
+ this.brandId = config.brand_id;
14
+ }
15
+ headers(extra) {
16
+ const h = {
17
+ "Content-Type": "application/json",
18
+ ...extra,
19
+ };
20
+ if (this.token) {
21
+ h["Authorization"] = `Bearer ${this.token}`;
22
+ }
23
+ if (this.brandId) {
24
+ h["X-Brand-ID"] = String(this.brandId);
25
+ }
26
+ return h;
27
+ }
28
+ async request(method, path, body, extraHeaders) {
29
+ if (!this.token) {
30
+ throw { detail: "Not authenticated. Run `opvs auth request` to get a token.", status: 401 };
31
+ }
32
+ const url = `${this.baseUrl}${path}`;
33
+ const res = await fetch(url, {
34
+ method,
35
+ headers: this.headers(extraHeaders),
36
+ body: body ? JSON.stringify(body) : undefined,
37
+ });
38
+ if (!res.ok) {
39
+ let detail;
40
+ try {
41
+ const err = (await res.json());
42
+ if (typeof err.detail === "string") {
43
+ detail = err.detail;
44
+ }
45
+ else if (Array.isArray(err.detail)) {
46
+ detail = err.detail.map((d) => d.msg || JSON.stringify(d)).join("; ");
47
+ }
48
+ else {
49
+ detail = res.statusText;
50
+ }
51
+ }
52
+ catch {
53
+ detail = res.statusText;
54
+ }
55
+ const error = { detail, status: res.status };
56
+ throw error;
57
+ }
58
+ return res;
59
+ }
60
+ async get(path, extraHeaders) {
61
+ return this.request("GET", path, undefined, extraHeaders);
62
+ }
63
+ async post(path, body, extraHeaders) {
64
+ return this.request("POST", path, body, extraHeaders);
65
+ }
66
+ async patch(path, body, extraHeaders) {
67
+ return this.request("PATCH", path, body, extraHeaders);
68
+ }
69
+ async put(path, body, extraHeaders) {
70
+ return this.request("PUT", path, body, extraHeaders);
71
+ }
72
+ async delete(path, extraHeaders) {
73
+ return this.request("DELETE", path, undefined, extraHeaders);
74
+ }
75
+ }
76
+ /**
77
+ * Unauthenticated POST — used for PAT request initiation.
78
+ */
79
+ export async function apiUnauthPost(baseUrl, path, body) {
80
+ const url = `${baseUrl.replace(/\/$/, "")}${path}`;
81
+ const res = await fetch(url, {
82
+ method: "POST",
83
+ headers: { "Content-Type": "application/json" },
84
+ body: JSON.stringify(body),
85
+ });
86
+ if (!res.ok) {
87
+ let detail;
88
+ try {
89
+ const err = (await res.json());
90
+ detail = err.detail || res.statusText;
91
+ }
92
+ catch {
93
+ detail = res.statusText;
94
+ }
95
+ const error = { detail, status: res.status };
96
+ throw error;
97
+ }
98
+ return res;
99
+ }
100
+ /**
101
+ * Unauthenticated GET with custom auth header — used for poll endpoint.
102
+ */
103
+ export async function apiUnauthGet(baseUrl, path, authHeader) {
104
+ const url = `${baseUrl.replace(/\/$/, "")}${path}`;
105
+ const headers = {};
106
+ if (authHeader) {
107
+ headers["Authorization"] = `Bearer ${authHeader}`;
108
+ }
109
+ const res = await fetch(url, { method: "GET", headers });
110
+ if (!res.ok) {
111
+ let detail;
112
+ try {
113
+ const err = (await res.json());
114
+ detail = err.detail || res.statusText;
115
+ }
116
+ catch {
117
+ detail = res.statusText;
118
+ }
119
+ const error = { detail, status: res.status };
120
+ throw error;
121
+ }
122
+ return res;
123
+ }
124
+ /** Create a new authenticated API client from current config. */
125
+ export function createClient() {
126
+ return new APIClient();
127
+ }
128
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Polling loop for PAT approval — waits for human to click approve/deny.
3
+ */
4
+ export interface PollResult {
5
+ status: "active" | "denied" | "expired" | "timeout";
6
+ token?: string;
7
+ scopes?: string[];
8
+ brand_id?: number;
9
+ brand_name?: string;
10
+ }
11
+ /**
12
+ * Poll the PAT request status endpoint until resolved or timed out.
13
+ * Prints dots to stderr to show progress.
14
+ */
15
+ export declare function pollForApproval(baseUrl: string, requestId: string, pollToken: string, timeoutMs?: number): Promise<PollResult>;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Polling loop for PAT approval — waits for human to click approve/deny.
3
+ */
4
+ import { apiUnauthGet } from "./api.js";
5
+ const POLL_INTERVAL_MS = 3000;
6
+ const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
7
+ /**
8
+ * Poll the PAT request status endpoint until resolved or timed out.
9
+ * Prints dots to stderr to show progress.
10
+ */
11
+ export async function pollForApproval(baseUrl, requestId, pollToken, timeoutMs = DEFAULT_TIMEOUT_MS) {
12
+ const deadline = Date.now() + timeoutMs;
13
+ process.stderr.write("Waiting for approval ");
14
+ while (Date.now() < deadline) {
15
+ try {
16
+ const res = await apiUnauthGet(baseUrl, `/api/v1/auth/pat/request/${requestId}/status`, pollToken);
17
+ const data = (await res.json());
18
+ if (data.status === "active" && data.token) {
19
+ process.stderr.write(" approved!\n");
20
+ return {
21
+ status: "active",
22
+ token: data.token,
23
+ scopes: data.scopes,
24
+ brand_id: data.brand_id,
25
+ brand_name: data.brand_name,
26
+ };
27
+ }
28
+ if (data.status === "denied") {
29
+ process.stderr.write(" denied.\n");
30
+ return { status: "denied" };
31
+ }
32
+ if (data.status === "expired") {
33
+ process.stderr.write(" expired.\n");
34
+ return { status: "expired" };
35
+ }
36
+ }
37
+ catch {
38
+ // Network error or server error — keep polling
39
+ }
40
+ process.stderr.write(".");
41
+ await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
42
+ }
43
+ process.stderr.write(" timed out.\n");
44
+ return { status: "timeout" };
45
+ }
46
+ //# sourceMappingURL=auth-poll.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-poll.js","sourceRoot":"","sources":["../../src/lib/auth-poll.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGxC,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAC9B,MAAM,kBAAkB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,YAAY;AAUtD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAe,EACf,SAAiB,EACjB,SAAiB,EACjB,SAAS,GAAG,kBAAkB;IAE9B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IAExC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAE9C,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,YAAY,CAC5B,OAAO,EACP,4BAA4B,SAAS,SAAS,EAC9C,SAAS,CACV,CAAC;YACF,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAsB,CAAC;YAErD,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC3C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;gBACrC,OAAO;oBACL,MAAM,EAAE,QAAQ;oBAChB,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;oBACvB,UAAU,EAAE,IAAI,CAAC,UAAU;iBAC5B,CAAC;YACJ,CAAC;YAED,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gBAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;gBACnC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;YAC9B,CAAC;YAED,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;gBACpC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YAC/B,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,+CAA+C;QACjD,CAAC;QAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC1B,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IACtC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Config file management: ~/.opvs/config.json
3
+ */
4
+ import { CLIConfig } from "../types.js";
5
+ export declare function getConfigPath(): string;
6
+ export declare function loadConfig(): CLIConfig;
7
+ export declare function saveConfig(config: Partial<CLIConfig>): void;
8
+ export declare function resetConfig(): void;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Config file management: ~/.opvs/config.json
3
+ */
4
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
5
+ import { homedir } from "node:os";
6
+ import { join } from "node:path";
7
+ import { DEFAULT_CONFIG } from "../types.js";
8
+ const CONFIG_DIR = join(homedir(), ".opvs");
9
+ const CONFIG_FILE = join(CONFIG_DIR, "config.json");
10
+ export function getConfigPath() {
11
+ return CONFIG_FILE;
12
+ }
13
+ export function loadConfig() {
14
+ if (!existsSync(CONFIG_FILE)) {
15
+ return { ...DEFAULT_CONFIG };
16
+ }
17
+ try {
18
+ const raw = readFileSync(CONFIG_FILE, "utf-8");
19
+ return { ...DEFAULT_CONFIG, ...JSON.parse(raw) };
20
+ }
21
+ catch {
22
+ return { ...DEFAULT_CONFIG };
23
+ }
24
+ }
25
+ export function saveConfig(config) {
26
+ const current = loadConfig();
27
+ const merged = { ...current, ...config };
28
+ if (!existsSync(CONFIG_DIR)) {
29
+ mkdirSync(CONFIG_DIR, { recursive: true });
30
+ }
31
+ writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2) + "\n");
32
+ }
33
+ export function resetConfig() {
34
+ if (!existsSync(CONFIG_DIR)) {
35
+ mkdirSync(CONFIG_DIR, { recursive: true });
36
+ }
37
+ writeFileSync(CONFIG_FILE, JSON.stringify(DEFAULT_CONFIG, null, 2) + "\n");
38
+ }
39
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAa,cAAc,EAAE,MAAM,aAAa,CAAC;AAExD,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;AAC5C,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAEpD,MAAM,UAAU,aAAa;IAC3B,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC/B,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC/C,OAAO,EAAE,GAAG,cAAc,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC/B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAA0B;IACnD,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,MAAM,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC;IACzC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC;IACD,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC;IACD,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AAC7E,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Agent type detection + system fingerprint for PAT requests.
3
+ */
4
+ import type { AgentFingerprint } from "../types.js";
5
+ /** Detect the AI agent type from environment variables. */
6
+ export declare function detectAgentType(): string;
7
+ /** Build a full agent fingerprint object. */
8
+ export declare function buildFingerprint(): AgentFingerprint;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Agent type detection + system fingerprint for PAT requests.
3
+ */
4
+ import { hostname, platform } from "node:os";
5
+ /** Detect the AI agent type from environment variables. */
6
+ export function detectAgentType() {
7
+ if (process.env.CLAUDE_CODE)
8
+ return "Claude Code";
9
+ if (process.env.CURSOR_SESSION || process.env.CURSOR_TRACE_ID)
10
+ return "Cursor";
11
+ if (process.env.WINDSURF_SESSION)
12
+ return "Windsurf";
13
+ if (process.env.CODEX_SESSION)
14
+ return "Codex";
15
+ if (process.env.TERM_PROGRAM === "vscode")
16
+ return "VS Code Terminal";
17
+ if (process.env.TERM_PROGRAM === "iTerm.app")
18
+ return "iTerm";
19
+ return "CLI";
20
+ }
21
+ /** Build a full agent fingerprint object. */
22
+ export function buildFingerprint() {
23
+ return {
24
+ agent_type: detectAgentType(),
25
+ hostname: hostname(),
26
+ cwd: process.cwd(),
27
+ platform: `${platform()} ${process.arch}`,
28
+ node_version: process.version,
29
+ cli_version: "0.1.0",
30
+ };
31
+ }
32
+ //# sourceMappingURL=fingerprint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../src/lib/fingerprint.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAG7C,2DAA2D;AAC3D,MAAM,UAAU,eAAe;IAC7B,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW;QAAE,OAAO,aAAa,CAAC;IAClD,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe;QAAE,OAAO,QAAQ,CAAC;IAC/E,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB;QAAE,OAAO,UAAU,CAAC;IACpD,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa;QAAE,OAAO,OAAO,CAAC;IAC9C,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,QAAQ;QAAE,OAAO,kBAAkB,CAAC;IACrE,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,WAAW;QAAE,OAAO,OAAO,CAAC;IAC7D,OAAO,KAAK,CAAC;AACf,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,gBAAgB;IAC9B,OAAO;QACL,UAAU,EAAE,eAAe,EAAE;QAC7B,QAAQ,EAAE,QAAQ,EAAE;QACpB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,QAAQ,EAAE,GAAG,QAAQ,EAAE,IAAI,OAAO,CAAC,IAAI,EAAE;QACzC,YAAY,EAAE,OAAO,CAAC,OAAO;QAC7B,WAAW,EAAE,OAAO;KACrB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Output formatters.
3
+ *
4
+ * View endpoints return pre-formatted YAML/MD text — we pass that through.
5
+ * For JSON API responses, we format as indented JSON or a basic table.
6
+ */
7
+ /** Print raw text (YAML/MD passthrough from view endpoints). */
8
+ export declare function printRaw(text: string): void;
9
+ /** Print a JSON response with indentation. */
10
+ export declare function printJson(data: unknown): void;
11
+ /** Determine the ?format= query param to append based on user preference. */
12
+ export declare function formatParam(format: string): string;
13
+ /** Build a URL with optional query params, merging format. */
14
+ export declare function buildUrl(base: string, params?: Record<string, string | number | boolean | undefined>, format?: string): string;
15
+ /**
16
+ * Handle a response that might be YAML/MD text or JSON.
17
+ * View endpoints return text/plain or text/yaml; others return JSON.
18
+ */
19
+ export declare function printResponse(res: Response, preferJson?: boolean): Promise<void>;
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Output formatters.
3
+ *
4
+ * View endpoints return pre-formatted YAML/MD text — we pass that through.
5
+ * For JSON API responses, we format as indented JSON or a basic table.
6
+ */
7
+ /** Print raw text (YAML/MD passthrough from view endpoints). */
8
+ export function printRaw(text) {
9
+ process.stdout.write(text);
10
+ if (!text.endsWith("\n"))
11
+ process.stdout.write("\n");
12
+ }
13
+ /** Print a JSON response with indentation. */
14
+ export function printJson(data) {
15
+ console.log(JSON.stringify(data, null, 2));
16
+ }
17
+ /** Determine the ?format= query param to append based on user preference. */
18
+ export function formatParam(format) {
19
+ if (format === "json")
20
+ return "";
21
+ return `format=${format}`;
22
+ }
23
+ /** Build a URL with optional query params, merging format. */
24
+ export function buildUrl(base, params, format) {
25
+ const parts = [];
26
+ if (params) {
27
+ for (const [k, v] of Object.entries(params)) {
28
+ if (v !== undefined && v !== "") {
29
+ parts.push(`${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`);
30
+ }
31
+ }
32
+ }
33
+ if (format && format !== "json") {
34
+ parts.push(`format=${format}`);
35
+ }
36
+ if (parts.length === 0)
37
+ return base;
38
+ return `${base}?${parts.join("&")}`;
39
+ }
40
+ /**
41
+ * Handle a response that might be YAML/MD text or JSON.
42
+ * View endpoints return text/plain or text/yaml; others return JSON.
43
+ */
44
+ export async function printResponse(res, preferJson = false) {
45
+ const ct = res.headers.get("content-type") || "";
46
+ if (preferJson || ct.includes("application/json")) {
47
+ const data = await res.json();
48
+ printJson(data);
49
+ }
50
+ else {
51
+ const text = await res.text();
52
+ printRaw(text);
53
+ }
54
+ }
55
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/lib/format.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,gEAAgE;AAChE,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC3B,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACvD,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,SAAS,CAAC,IAAa;IACrC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,EAAE,CAAC;IACjC,OAAO,UAAU,MAAM,EAAE,CAAC;AAC5B,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,QAAQ,CACtB,IAAY,EACZ,MAA8D,EAC9D,MAAe;IAEf,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,MAAM,EAAE,CAAC;QACX,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5C,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;gBAChC,KAAK,CAAC,IAAI,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,IAAI,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC1E,CAAC;QACH,CAAC;IACH,CAAC;IACD,IAAI,MAAM,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,UAAU,MAAM,EAAE,CAAC,CAAC;IACjC,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,OAAO,GAAG,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAa,EAAE,UAAU,GAAG,KAAK;IACnE,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;IACjD,IAAI,UAAU,IAAI,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,SAAS,CAAC,IAAI,CAAC,CAAC;IAClB,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC,CAAC;IACjB,CAAC;AACH,CAAC"}
@@ -0,0 +1,35 @@
1
+ /** Shared TypeScript interfaces for @opvs/cli */
2
+ export interface CLIConfig {
3
+ api_url: string;
4
+ token: string;
5
+ brand_id: number | null;
6
+ brand_name: string;
7
+ format: "yaml" | "json" | "md";
8
+ }
9
+ export declare const DEFAULT_CONFIG: CLIConfig;
10
+ export interface PATRequestResponse {
11
+ request_id: string;
12
+ status: string;
13
+ poll_token: string;
14
+ expires_at: string;
15
+ }
16
+ export interface PATStatusResponse {
17
+ status: "pending" | "active" | "denied" | "expired";
18
+ token?: string;
19
+ scopes?: string[];
20
+ token_expires_at?: string;
21
+ brand_id?: number;
22
+ brand_name?: string;
23
+ }
24
+ export interface AgentFingerprint {
25
+ agent_type: string;
26
+ hostname: string;
27
+ cwd: string;
28
+ platform: string;
29
+ node_version: string;
30
+ cli_version: string;
31
+ }
32
+ export interface APIError {
33
+ detail: string;
34
+ status: number;
35
+ }