@bussolabs/closeyourit-cli 0.0.12 → 0.0.14
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/README.md +7 -0
- package/dist/commands/ideas/comment-delete.d.ts +14 -0
- package/dist/commands/ideas/comment-delete.js +30 -0
- package/dist/commands/ideas/comment.d.ts +13 -0
- package/dist/commands/ideas/comment.js +29 -0
- package/dist/commands/ideas/comments.d.ts +12 -0
- package/dist/commands/ideas/comments.js +45 -0
- package/dist/commands/ideas/convert.d.ts +17 -0
- package/dist/commands/ideas/convert.js +48 -0
- package/dist/commands/ideas/create.d.ts +11 -0
- package/dist/commands/ideas/create.js +27 -0
- package/dist/commands/ideas/list.d.ts +12 -0
- package/dist/commands/ideas/list.js +40 -0
- package/dist/commands/ideas/show.d.ts +12 -0
- package/dist/commands/ideas/show.js +28 -0
- package/dist/commands/ideas/unvote.d.ts +12 -0
- package/dist/commands/ideas/unvote.js +24 -0
- package/dist/commands/ideas/vote.d.ts +12 -0
- package/dist/commands/ideas/vote.js +24 -0
- package/dist/commands/kb/ask.d.ts +10 -0
- package/dist/commands/kb/ask.js +45 -0
- package/dist/commands/kb/create.d.ts +13 -0
- package/dist/commands/kb/create.js +48 -0
- package/dist/commands/kb/delete.d.ts +12 -0
- package/dist/commands/kb/delete.js +25 -0
- package/dist/commands/kb/list.d.ts +12 -0
- package/dist/commands/kb/list.js +35 -0
- package/dist/commands/kb/search.d.ts +16 -0
- package/dist/commands/kb/search.js +48 -0
- package/dist/commands/kb/show.d.ts +9 -0
- package/dist/commands/kb/show.js +40 -0
- package/dist/commands/kb/update.d.ts +15 -0
- package/dist/commands/kb/update.js +53 -0
- package/dist/lib/knowledge.d.ts +22 -0
- package/dist/lib/knowledge.js +54 -0
- package/oclif.manifest.json +1333 -431
- package/opencli.json +349 -1
- package/package.json +7 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const base_1 = require("../../base");
|
|
5
|
+
const knowledge_1 = require("../../lib/knowledge");
|
|
6
|
+
class KbList extends base_1.BaseCommand {
|
|
7
|
+
static description = 'List knowledge pages across the projects you can see';
|
|
8
|
+
static examples = [
|
|
9
|
+
'<%= config.bin %> kb list',
|
|
10
|
+
'<%= config.bin %> kb list --project acme-api --kind decision',
|
|
11
|
+
'<%= config.bin %> kb list --kind note,guide --per 50 --json',
|
|
12
|
+
];
|
|
13
|
+
static flags = {
|
|
14
|
+
// Optional (the endpoint is cross-project): omit it to span every visible project.
|
|
15
|
+
project: core_1.Flags.string({ char: 'p', description: 'Filter by project (key or UUID)' }),
|
|
16
|
+
kind: core_1.Flags.string({ description: 'Filter by kind: note|decision|guide (repeatable or comma-separated)', multiple: true }),
|
|
17
|
+
per: core_1.Flags.integer({ description: 'Page size' }),
|
|
18
|
+
...base_1.pageFlag,
|
|
19
|
+
};
|
|
20
|
+
async run() {
|
|
21
|
+
const { flags } = await this.parse(KbList);
|
|
22
|
+
const query = (0, knowledge_1.buildPagesQuery)({
|
|
23
|
+
kinds: (0, knowledge_1.normalizeKinds)(flags.kind),
|
|
24
|
+
page: flags.page,
|
|
25
|
+
per: flags.per,
|
|
26
|
+
project: flags.project,
|
|
27
|
+
});
|
|
28
|
+
const res = await this.api.get(`/cli/v1/knowledge/pages?${query}`);
|
|
29
|
+
if (!this.jsonEnabled()) {
|
|
30
|
+
this.log((0, knowledge_1.renderPagesTable)(res.data ?? []));
|
|
31
|
+
}
|
|
32
|
+
return res;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.default = KbList;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base';
|
|
2
|
+
export default class KbSearch extends BaseCommand {
|
|
3
|
+
static strict: boolean;
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: string[];
|
|
6
|
+
static args: {
|
|
7
|
+
query: import("@oclif/core/lib/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
8
|
+
};
|
|
9
|
+
static flags: {
|
|
10
|
+
page: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
|
+
project: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
12
|
+
kind: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
13
|
+
per: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
14
|
+
};
|
|
15
|
+
run(): Promise<unknown>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const base_1 = require("../../base");
|
|
5
|
+
const knowledge_1 = require("../../lib/knowledge");
|
|
6
|
+
class KbSearch extends base_1.BaseCommand {
|
|
7
|
+
// Variadic query: every positional word is joined into a single search string.
|
|
8
|
+
static strict = false;
|
|
9
|
+
static description = 'Search knowledge pages (semantic when available, ILIKE fallback on the title otherwise)';
|
|
10
|
+
static examples = [
|
|
11
|
+
'<%= config.bin %> kb search kamal deploy rollback',
|
|
12
|
+
'<%= config.bin %> kb search "connection pool timeout" --project acme-api',
|
|
13
|
+
'<%= config.bin %> kb search retry backoff --kind decision --json',
|
|
14
|
+
];
|
|
15
|
+
// Non-required: with strict = false the arg validation is off, so we guard the empty case ourselves.
|
|
16
|
+
static args = {
|
|
17
|
+
query: core_1.Args.string({ description: 'Search query (all positional words are joined)' }),
|
|
18
|
+
};
|
|
19
|
+
static flags = {
|
|
20
|
+
project: core_1.Flags.string({ char: 'p', description: 'Filter by project (key or UUID)' }),
|
|
21
|
+
kind: core_1.Flags.string({ description: 'Filter by kind: note|decision|guide (repeatable or comma-separated)', multiple: true }),
|
|
22
|
+
per: core_1.Flags.integer({ description: 'Page size' }),
|
|
23
|
+
...base_1.pageFlag,
|
|
24
|
+
};
|
|
25
|
+
async run() {
|
|
26
|
+
const { argv, flags } = await this.parse(KbSearch);
|
|
27
|
+
const q = argv.join(' ').trim();
|
|
28
|
+
if (q === '')
|
|
29
|
+
this.error('Provide a search query (e.g. "kb search kamal rollback").', { exit: 2 });
|
|
30
|
+
const query = (0, knowledge_1.buildPagesQuery)({
|
|
31
|
+
kinds: (0, knowledge_1.normalizeKinds)(flags.kind),
|
|
32
|
+
page: flags.page,
|
|
33
|
+
per: flags.per,
|
|
34
|
+
project: flags.project,
|
|
35
|
+
q,
|
|
36
|
+
});
|
|
37
|
+
const res = await this.api.get(`/cli/v1/knowledge/pages?${query}`);
|
|
38
|
+
if (!this.jsonEnabled()) {
|
|
39
|
+
// meta.search tells us whether the server ran a semantic query or fell back to a title ILIKE.
|
|
40
|
+
if (res.meta?.search === 'like') {
|
|
41
|
+
this.log('(semantic search unavailable — showing title matches)');
|
|
42
|
+
}
|
|
43
|
+
this.log((0, knowledge_1.renderPagesTable)(res.data ?? []));
|
|
44
|
+
}
|
|
45
|
+
return res;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.default = KbSearch;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base';
|
|
2
|
+
export default class KbShow extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
run(): Promise<unknown>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const base_1 = require("../../base");
|
|
5
|
+
const output_1 = require("../../lib/output");
|
|
6
|
+
class KbShow extends base_1.BaseCommand {
|
|
7
|
+
static description = 'Show a single knowledge page: metadata header then the raw markdown body';
|
|
8
|
+
static examples = [
|
|
9
|
+
'<%= config.bin %> kb show <page-id>',
|
|
10
|
+
'<%= config.bin %> kb show <page-id> --json',
|
|
11
|
+
];
|
|
12
|
+
static args = {
|
|
13
|
+
id: core_1.Args.string({ description: 'Knowledge page id', required: true }),
|
|
14
|
+
};
|
|
15
|
+
async run() {
|
|
16
|
+
const { args } = await this.parse(KbShow);
|
|
17
|
+
const res = await this.api.get(`/cli/v1/knowledge/pages/${encodeURIComponent(args.id)}`);
|
|
18
|
+
const page = res.data ?? {};
|
|
19
|
+
if (!this.jsonEnabled()) {
|
|
20
|
+
// Header first (scalar fields only), then the body on its own so the markdown stays intact.
|
|
21
|
+
this.log((0, output_1.renderRecord)({
|
|
22
|
+
id: page.id,
|
|
23
|
+
title: page.title,
|
|
24
|
+
kind: page.kind,
|
|
25
|
+
project: page.project,
|
|
26
|
+
project_name: page.project_name,
|
|
27
|
+
author: page.author,
|
|
28
|
+
created_at: page.created_at,
|
|
29
|
+
updated_at: page.updated_at,
|
|
30
|
+
}));
|
|
31
|
+
const body = page.body;
|
|
32
|
+
if (body !== null && body !== undefined && String(body).trim() !== '') {
|
|
33
|
+
this.log('');
|
|
34
|
+
this.log((0, output_1.sanitizeMultiline)(body));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return res;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.default = KbShow;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base';
|
|
2
|
+
export default class KbUpdate extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
title: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
10
|
+
kind: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
|
+
body: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
12
|
+
'body-file': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
13
|
+
};
|
|
14
|
+
run(): Promise<unknown>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const promises_1 = require("node:fs/promises");
|
|
4
|
+
const core_1 = require("@oclif/core");
|
|
5
|
+
const base_1 = require("../../base");
|
|
6
|
+
const output_1 = require("../../lib/output");
|
|
7
|
+
class KbUpdate extends base_1.BaseCommand {
|
|
8
|
+
static description = 'Update a knowledge page (only the fields you pass; the others keep their current value)';
|
|
9
|
+
static examples = [
|
|
10
|
+
'<%= config.bin %> kb update <page-id> --title "New title"',
|
|
11
|
+
'<%= config.bin %> kb update <page-id> --kind decision --body-file ./adr.md',
|
|
12
|
+
];
|
|
13
|
+
static args = {
|
|
14
|
+
id: core_1.Args.string({ description: 'Knowledge page id', required: true }),
|
|
15
|
+
};
|
|
16
|
+
static flags = {
|
|
17
|
+
title: core_1.Flags.string({ description: 'New title' }),
|
|
18
|
+
kind: core_1.Flags.string({ description: 'New kind: note|decision|guide' }),
|
|
19
|
+
body: core_1.Flags.string({ description: 'New body (markdown)' }),
|
|
20
|
+
'body-file': core_1.Flags.string({ description: 'Read the new body (markdown) from a local file' }),
|
|
21
|
+
};
|
|
22
|
+
async run() {
|
|
23
|
+
const { args, flags } = await this.parse(KbUpdate);
|
|
24
|
+
let body = flags.body;
|
|
25
|
+
if (body === undefined && flags['body-file'] !== undefined) {
|
|
26
|
+
try {
|
|
27
|
+
body = await (0, promises_1.readFile)(flags['body-file'], 'utf8');
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
this.error(`File not found or unreadable: ${flags['body-file']}`, { exit: 2 });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (flags.title === undefined && flags.kind === undefined && body === undefined) {
|
|
34
|
+
this.error('Provide at least one of --title, --kind, --body or --body-file.', { exit: 2 });
|
|
35
|
+
}
|
|
36
|
+
// The backend expects the full title/body/kind on update → read the current page and merge,
|
|
37
|
+
// so a partial edit (e.g. only --title) doesn't blank out the other fields.
|
|
38
|
+
const base = `/cli/v1/knowledge/pages/${encodeURIComponent(args.id)}`;
|
|
39
|
+
const current = await this.api.get(base);
|
|
40
|
+
const page = current.data ?? {};
|
|
41
|
+
const res = await this.api.put(base, {
|
|
42
|
+
title: flags.title ?? page.title,
|
|
43
|
+
kind: flags.kind ?? page.kind,
|
|
44
|
+
body: body ?? page.body,
|
|
45
|
+
});
|
|
46
|
+
if (!this.jsonEnabled()) {
|
|
47
|
+
this.log('Knowledge page updated:');
|
|
48
|
+
this.log((0, output_1.renderRecord)(res.data ?? {}));
|
|
49
|
+
}
|
|
50
|
+
return res;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.default = KbUpdate;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Knowledge page kinds accepted by the backend (Knowledge::Page). */
|
|
2
|
+
export declare const KNOWLEDGE_KINDS: readonly ["note", "decision", "guide"];
|
|
3
|
+
/**
|
|
4
|
+
* Flatten a repeatable + comma-separated `--kind` flag into a clean list.
|
|
5
|
+
* `--kind note --kind decision,guide` → ['note', 'decision', 'guide'].
|
|
6
|
+
*/
|
|
7
|
+
export declare function normalizeKinds(values?: string[]): string[];
|
|
8
|
+
/** Collapse whitespace and truncate a cell so the list table stays single-line. */
|
|
9
|
+
export declare function truncate(value: string, max?: number): string;
|
|
10
|
+
/**
|
|
11
|
+
* Build the shared query string for `kb list` / `kb search`. Kinds go out as the
|
|
12
|
+
* `kind[]` array param; `page` is always sent, `per`/`project`/`q` only when set.
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildPagesQuery(opts: {
|
|
15
|
+
kinds: string[];
|
|
16
|
+
page: number;
|
|
17
|
+
per?: number;
|
|
18
|
+
project?: string;
|
|
19
|
+
q?: string;
|
|
20
|
+
}): string;
|
|
21
|
+
/** Render the shared list/search table: TITLE, KIND, PROJECT, AUTHOR, UPDATED. */
|
|
22
|
+
export declare function renderPagesTable(pages: Array<Record<string, unknown>>): string;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KNOWLEDGE_KINDS = void 0;
|
|
4
|
+
exports.normalizeKinds = normalizeKinds;
|
|
5
|
+
exports.truncate = truncate;
|
|
6
|
+
exports.buildPagesQuery = buildPagesQuery;
|
|
7
|
+
exports.renderPagesTable = renderPagesTable;
|
|
8
|
+
const output_1 = require("./output");
|
|
9
|
+
/** Knowledge page kinds accepted by the backend (Knowledge::Page). */
|
|
10
|
+
exports.KNOWLEDGE_KINDS = ['note', 'decision', 'guide'];
|
|
11
|
+
/**
|
|
12
|
+
* Flatten a repeatable + comma-separated `--kind` flag into a clean list.
|
|
13
|
+
* `--kind note --kind decision,guide` → ['note', 'decision', 'guide'].
|
|
14
|
+
*/
|
|
15
|
+
function normalizeKinds(values) {
|
|
16
|
+
if (!values)
|
|
17
|
+
return [];
|
|
18
|
+
return values
|
|
19
|
+
.flatMap((value) => value.split(','))
|
|
20
|
+
.map((value) => value.trim())
|
|
21
|
+
.filter((value) => value.length > 0);
|
|
22
|
+
}
|
|
23
|
+
/** Collapse whitespace and truncate a cell so the list table stays single-line. */
|
|
24
|
+
function truncate(value, max = 60) {
|
|
25
|
+
const flat = value.replace(/\s+/g, ' ').trim();
|
|
26
|
+
return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Build the shared query string for `kb list` / `kb search`. Kinds go out as the
|
|
30
|
+
* `kind[]` array param; `page` is always sent, `per`/`project`/`q` only when set.
|
|
31
|
+
*/
|
|
32
|
+
function buildPagesQuery(opts) {
|
|
33
|
+
const query = new URLSearchParams();
|
|
34
|
+
query.set('page', String(opts.page));
|
|
35
|
+
if (opts.per !== undefined)
|
|
36
|
+
query.set('per', String(opts.per));
|
|
37
|
+
if (opts.project)
|
|
38
|
+
query.set('project', opts.project);
|
|
39
|
+
for (const kind of opts.kinds)
|
|
40
|
+
query.append('kind[]', kind);
|
|
41
|
+
if (opts.q)
|
|
42
|
+
query.set('q', opts.q);
|
|
43
|
+
return query.toString();
|
|
44
|
+
}
|
|
45
|
+
/** Render the shared list/search table: TITLE, KIND, PROJECT, AUTHOR, UPDATED. */
|
|
46
|
+
function renderPagesTable(pages) {
|
|
47
|
+
return (0, output_1.renderTable)(['TITLE', 'KIND', 'PROJECT', 'AUTHOR', 'UPDATED'], pages.map((page) => [
|
|
48
|
+
truncate(String(page.title ?? '')),
|
|
49
|
+
String(page.kind ?? ''),
|
|
50
|
+
String(page.project ?? ''),
|
|
51
|
+
String(page.author ?? ''),
|
|
52
|
+
String(page.updated_at ?? ''),
|
|
53
|
+
]));
|
|
54
|
+
}
|