@bussolabs/closeyourit-cli 0.24.2 → 0.25.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/README.md CHANGED
@@ -162,6 +162,8 @@ CLOSEYOURIT_TOKEN=cyi_u_… CLOSEYOURIT_API_URL=https://www.closeyour.it \
162
162
  | `kb related <id> [--question <q>] [--links-only]` | Pages to read next: linked with `[[wiki links]]` plus close matches by meaning. |
163
163
  | `kb create [--project <id\|key>…] [--group <id\|name>…] [--tag <tag>…] --title <t> [--kind note\|decision\|guide] (--body <md> \| --body-file <path>) [--tech-spec <md> \| --tech-spec-file <path>] [--in-review] [--review-note <line>] [--author-origin <name>]` | Create a knowledge page (optional technical section, kept separate from the body). `--project`, `--group` and `--tag` are repeatable — a page can belong to several projects and groups at once, and to groups alone; at least one project or group is required. Length caps: title 255, body 4000, technical section 1500, review note 240 characters — every field over the cap is listed at once, before the call. With `--in-review` the page waits for a human and stays out of search, answers and related panels. `--author-origin` declares the assistant or skill that wrote the text, which is not the owner of the token. |
164
164
  | `kb publish --project <id\|key> --publication-key <key> --title <t> [--kind note\|decision\|guide] (--body <md> \| --body-file <path>)` | Create or update a knowledge page in one atomic call, keyed by a stable `--publication-key` (1-255 URL-safe characters). Safe to repeat: the same key always lands on the same page, and the output says whether it was `created` or `updated`. Exactly one body source is required. Omitting `--kind` keeps the kind the page already has (a new page is a `note`). Same title/body caps as `kb create`. |
165
+ | `kb approve <id>` | Accept a page waiting for review: it enters search, answers and related panels. A human decision: a service token is refused, and a page the automatic reviewer rejected must be fixed and saved first. |
166
+ | `kb reject <id>` | Discard a page waiting for review: it stays archived as rejected, out of search and answers, so it is not proposed again. Nothing is deleted. |
165
167
  | `kb consolidate <id> --path <doc-path>` | Mark an accepted page as written to the versioned docs, recording where the document lives. |
166
168
  | `kb update <id> [--title] [--kind] [--body \| --body-file] [--tech-spec \| --tech-spec-file] [--project <id\|key>…] [--group <id\|name>…] [--tag <tag>…] [--author-origin <name>]` | Update a page (unpassed fields keep their current value — including projects, groups, tags and attachments). Passing `--project`, `--group` or `--tag` **replaces** that list with what you name; `--tag ""` clears the tags. Changing only scope or tags never rewrites the text, so a concurrent edit is not overwritten. Same length caps as `kb create`; text already over the cap is refused only if it grows. |
167
169
  | `kb delete <id> --confirm` | Delete a knowledge page (irreversible). |
package/dist/base.js CHANGED
@@ -207,10 +207,12 @@ class BaseCommand extends core_1.Command {
207
207
  async catch(error) {
208
208
  if (error instanceof api_1.ApiRequestError) {
209
209
  if (this.jsonEnabled()) {
210
- this.logJson({ error: { code: error.code, message: error.message } });
210
+ this.logJson({ error: { code: error.code, message: error.message, ...(error.details === undefined ? {} : { details: error.details }) } });
211
211
  }
212
212
  else {
213
213
  this.logToStderr(`${error.code}: ${error.message}`);
214
+ for (const line of reviewVerdictLines(error))
215
+ this.logToStderr(line);
214
216
  }
215
217
  return this.exit(1);
216
218
  }
@@ -253,3 +255,31 @@ class BaseCommand extends core_1.Command {
253
255
  }
254
256
  }
255
257
  exports.BaseCommand = BaseCommand;
258
+ /**
259
+ * The automatic reviewer of knowledge pages (R422-KNOWLEDGE-013, CYRA-764) answers with the whole
260
+ * verdict in `details`: every rule violated, the format it recognised, a suggested title, the page it
261
+ * looks like a duplicate of. The message carries only the first three rules, so a human reading the
262
+ * terminal would otherwise have to open the site to learn what to fix.
263
+ */
264
+ function reviewVerdictLines(error) {
265
+ if (error.code !== 'R422-KNOWLEDGE-013' || typeof error.details !== 'object' || error.details === null)
266
+ return [];
267
+ const details = error.details;
268
+ const lines = [];
269
+ const violations = Array.isArray(details.violations) ? details.violations : [];
270
+ if (violations.length > 0) {
271
+ lines.push('Rules violated:');
272
+ for (const v of violations)
273
+ lines.push(` ${v.code ?? '?'}${v.blocking === false ? ' (warning)' : ''}: ${v.message ?? ''}`);
274
+ }
275
+ if (details.format && details.format !== 'unknown')
276
+ lines.push(`Format recognised: ${details.format}`);
277
+ if (details.suggested_title)
278
+ lines.push(`Suggested title: ${details.suggested_title}`);
279
+ if (details.duplicate_of)
280
+ lines.push(`Looks like a duplicate of: ${details.duplicate_of}`);
281
+ if (Array.isArray(details.split_suggestion) && details.split_suggestion.length > 0) {
282
+ lines.push(`Split into: ${details.split_suggestion.join(' · ')}`);
283
+ }
284
+ return lines;
285
+ }
@@ -0,0 +1,15 @@
1
+ import { BaseCommand } from '../../base';
2
+ /**
3
+ * First step of the review flow: a page proposed with `kb create --in-review` enters the knowledge
4
+ * (search, answers, related panels). The server insists the decision comes from a person: a service
5
+ * token gets R403-KNOWLEDGE-005, and a page the automatic reviewer rejected must be fixed and saved
6
+ * first (R422-KNOWLEDGE-009).
7
+ */
8
+ export default class KbApprove extends BaseCommand {
9
+ static args: {
10
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
11
+ };
12
+ static description: string;
13
+ static examples: string[];
14
+ run(): Promise<unknown>;
15
+ }
@@ -0,0 +1,28 @@
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
+ /**
7
+ * First step of the review flow: a page proposed with `kb create --in-review` enters the knowledge
8
+ * (search, answers, related panels). The server insists the decision comes from a person: a service
9
+ * token gets R403-KNOWLEDGE-005, and a page the automatic reviewer rejected must be fixed and saved
10
+ * first (R422-KNOWLEDGE-009).
11
+ */
12
+ class KbApprove extends base_1.BaseCommand {
13
+ static args = {
14
+ id: core_1.Args.string({ description: 'Knowledge page id', required: true }),
15
+ };
16
+ static description = 'Accept a page waiting for review: it enters search, answers and related panels';
17
+ static examples = ['<%= config.bin %> kb approve <page-id>', '<%= config.bin %> kb approve <page-id> --json'];
18
+ async run() {
19
+ const { args } = await this.parse(KbApprove);
20
+ const res = await this.api.post(`/cli/v1/knowledge/pages/${args.id}/approve`);
21
+ if (!this.jsonEnabled()) {
22
+ this.log('Knowledge page accepted:');
23
+ this.log((0, output_1.renderRecord)(res.data ?? {}));
24
+ }
25
+ return res;
26
+ }
27
+ }
28
+ exports.default = KbApprove;
@@ -0,0 +1,14 @@
1
+ import { BaseCommand } from '../../base';
2
+ /**
3
+ * Mirror of `kb approve`: the proposal stays archived as rejected — out of search, answers, related
4
+ * panels and lists — so whoever proposes can see it when hunting duplicates and not propose it again.
5
+ * Nothing is deleted (that is `kb delete`). A human decision, like approve.
6
+ */
7
+ export default class KbReject extends BaseCommand {
8
+ static args: {
9
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
10
+ };
11
+ static description: string;
12
+ static examples: string[];
13
+ run(): Promise<unknown>;
14
+ }
@@ -0,0 +1,27 @@
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
+ /**
7
+ * Mirror of `kb approve`: the proposal stays archived as rejected — out of search, answers, related
8
+ * panels and lists — so whoever proposes can see it when hunting duplicates and not propose it again.
9
+ * Nothing is deleted (that is `kb delete`). A human decision, like approve.
10
+ */
11
+ class KbReject extends base_1.BaseCommand {
12
+ static args = {
13
+ id: core_1.Args.string({ description: 'Knowledge page id', required: true }),
14
+ };
15
+ static description = 'Discard a page waiting for review: it stays archived as rejected, out of search and answers';
16
+ static examples = ['<%= config.bin %> kb reject <page-id>', '<%= config.bin %> kb reject <page-id> --json'];
17
+ async run() {
18
+ const { args } = await this.parse(KbReject);
19
+ const res = await this.api.post(`/cli/v1/knowledge/pages/${args.id}/reject`);
20
+ if (!this.jsonEnabled()) {
21
+ this.log('Knowledge page rejected:');
22
+ this.log((0, output_1.renderRecord)(res.data ?? {}));
23
+ }
24
+ return res;
25
+ }
26
+ }
27
+ exports.default = KbReject;