@bussolabs/closeyourit-cli 0.9.0 → 0.11.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 +6 -14
- package/dist/commands/guidance/show.d.ts +9 -0
- package/dist/commands/guidance/show.js +26 -0
- package/dist/commands/kb/show.js +6 -0
- package/dist/commands/projects/github.js +1 -0
- package/dist/commands/projects/show.d.ts +7 -0
- package/dist/commands/projects/show.js +37 -2
- package/dist/commands/secrets/list.d.ts +1 -0
- package/dist/commands/secrets/list.js +5 -1
- package/dist/commands/tickets/show.js +6 -0
- package/dist/lib/guidance.d.ts +25 -0
- package/dist/lib/guidance.js +51 -0
- package/oclif.manifest.json +3656 -4159
- package/package.json +7 -1
- package/dist/commands/agents/assign.d.ts +0 -13
- package/dist/commands/agents/assign.js +0 -25
- package/dist/commands/agents/create.d.ts +0 -22
- package/dist/commands/agents/create.js +0 -58
- package/dist/commands/agents/delete.d.ts +0 -12
- package/dist/commands/agents/delete.js +0 -25
- package/dist/commands/agents/list.d.ts +0 -10
- package/dist/commands/agents/list.js +0 -34
- package/dist/commands/agents/runs/list.d.ts +0 -12
- package/dist/commands/agents/runs/list.js +0 -32
- package/dist/commands/agents/runs/show.d.ts +0 -10
- package/dist/commands/agents/runs/show.js +0 -21
- package/dist/commands/agents/show.d.ts +0 -9
- package/dist/commands/agents/show.js +0 -20
- package/dist/commands/agents/update.d.ts +0 -23
- package/dist/commands/agents/update.js +0 -59
package/README.md
CHANGED
|
@@ -43,17 +43,17 @@ CLOSEYOURIT_TOKEN=cyi_u_… CLOSEYOURIT_API_URL=https://www.closeyour.it \
|
|
|
43
43
|
| `logout` | Clear the locally stored token and identity. |
|
|
44
44
|
| `whoami` | Show account, organization, token prefix and permissions. |
|
|
45
45
|
| `projects list [--page]` | List visible projects. |
|
|
46
|
-
| `projects show <id\|key>` | Show one project. |
|
|
46
|
+
| `projects show <id\|key>` | Show one project, plus its declared environments and per-environment capabilities. |
|
|
47
47
|
| `projects create <name> --key <key> [--group <id\|name>] [--color] [--description] [--roadmap-enabled] [--quick-bug-report-enabled]` | Create a project (optionally inside a group). |
|
|
48
48
|
| `projects update --project <id\|key> [--name] [--key] [--color] [--description] [--group] [--roadmap-enabled] [--quick-bug-report-enabled]` | Update a project (only the passed fields change). |
|
|
49
49
|
| `projects link-server --project <id\|key> --host-id <id> --environment-id <id>` | Link a server host to a declared project environment (uptime). |
|
|
50
50
|
| `projects unlink-server <link-id> --project <id\|key> --confirm` | Unlink a server host from the project. |
|
|
51
51
|
| `projects settings show --project <id\|key>` | Show a project's settings (log/analytics retention + feature flags). |
|
|
52
52
|
| `projects settings update --project <id\|key> [--logs-retention-days] [--analytics-retention-days] [--roadmap-enabled] [--quick-bug-report-enabled] [--analytics-enabled]` | Update a project's settings (only the passed fields change). |
|
|
53
|
-
| `projects github --project <id\|key>` | Show a project's GitHub integration (repo link + tag→release binding rules). |
|
|
53
|
+
| `projects github --project <id\|key>` | Show a project's GitHub integration (repo link + secrets-sync state + tag→release binding rules). |
|
|
54
54
|
| `projects github-connect --project <id\|key> --repository <owner/name>` | Connect a project to a repository visible to the organization's GitHub App. |
|
|
55
55
|
| `projects github-map [--connected-only]` | List every visible CloseYourIt project and its connected GitHub repository; automatically fetches all pages. |
|
|
56
|
-
| `projects github-update --project <id\|key> [--default-branch] [--production-environment-id] [--staging-environment-id] [--sync-enabled] [--tag-binding-enabled] [--autoclose-on-merge]` | Update a project's GitHub binding rules (only the passed fields change). |
|
|
56
|
+
| `projects github-update --project <id\|key> [--default-branch] [--production-environment-id] [--staging-environment-id] [--sync-enabled] [--sync-secrets] [--tag-binding-enabled] [--autoclose-on-merge]` | Update a project's GitHub binding rules (only the passed fields change; `--sync-secrets`/`--no-sync-secrets` toggles pushing vault secrets to GitHub). |
|
|
57
57
|
| `groups list [--page]` | List groups (macro-projects) in your org. |
|
|
58
58
|
| `groups create <name> [--color] [--roadmap-enabled]` | Create a group (container of related projects, e.g. "DriverOne"). |
|
|
59
59
|
| `groups update <id\|name> [--name] [--color] [--roadmap-enabled]` | Update a group (rename, recolor, toggle roadmap). |
|
|
@@ -117,10 +117,10 @@ CLOSEYOURIT_TOKEN=cyi_u_… CLOSEYOURIT_API_URL=https://www.closeyour.it \
|
|
|
117
117
|
| `logs unlink <id> <link-id> --confirm` | Remove a manual log link. |
|
|
118
118
|
| `kb list [--project <id\|key>] [--kind] [--per] [--page]` | List knowledge pages. Cross-project: omit `--project` for every visible project. |
|
|
119
119
|
| `kb search <query…> [--project <id\|key>] [--kind] [--per] [--page] [--with-related]` | Search knowledge pages (semantic when available, title ILIKE fallback). |
|
|
120
|
-
| `kb show <id> [--related] [--question <q>]` | Show one knowledge page: metadata header
|
|
120
|
+
| `kb show <id> [--related] [--question <q>]` | Show one knowledge page: metadata header, raw markdown body, then the technical section. |
|
|
121
121
|
| `kb related <id> [--question <q>] [--links-only]` | Pages to read next: linked with `[[wiki links]]` plus close matches by meaning. |
|
|
122
|
-
| `kb create --project <id\|key> --title <t> [--kind note\|decision\|guide] (--body <md> \| --body-file <path>)` | Create a knowledge page. |
|
|
123
|
-
| `kb update <id> [--title] [--kind] [--body \| --body-file]` | Update a page (unpassed fields keep their current value). |
|
|
122
|
+
| `kb create --project <id\|key> --title <t> [--kind note\|decision\|guide] (--body <md> \| --body-file <path>) [--tech-spec <md> \| --tech-spec-file <path>]` | Create a knowledge page (optional technical section, kept separate from the body). |
|
|
123
|
+
| `kb update <id> [--title] [--kind] [--body \| --body-file] [--tech-spec \| --tech-spec-file]` | Update a page (unpassed fields keep their current value). |
|
|
124
124
|
| `kb delete <id> --confirm` | Delete a knowledge page (irreversible). |
|
|
125
125
|
| `kb ask <question…>` | Ask a question; the AI answers from the knowledge base and cites the pages it used. |
|
|
126
126
|
| `servers list [--status] [--page]` | List the monitored servers (fleet snapshot: status, cpu/mem/disk, last seen). |
|
|
@@ -133,14 +133,6 @@ CLOSEYOURIT_TOKEN=cyi_u_… CLOSEYOURIT_API_URL=https://www.closeyour.it \
|
|
|
133
133
|
| `servers tokens list` | List the fleet enrollment tokens. |
|
|
134
134
|
| `servers tokens create <name>` | Create an enrollment token (secret shown once). |
|
|
135
135
|
| `servers tokens revoke <id> --confirm` | Revoke an enrollment token. |
|
|
136
|
-
| `agents list [--kind claude\|shell] [--page]` | List the automation agents in your org. |
|
|
137
|
-
| `agents show <id>` | Show one automation agent. |
|
|
138
|
-
| `agents create --name --slug --run --schedule [--kind] [--timeout] [--model] [--permission-mode] [--allowed-tool…] [--on-failure] [--project <id\|key>…] [--group <id\|name>…] [--catch-up] [--no-enabled]` | Create an agent (executed by closeyourit-automator). |
|
|
139
|
-
| `agents update <id> [--name] [--slug] [--kind] [--run] [--schedule] [--timeout] [--model] [--permission-mode] [--allowed-tool…] [--on-failure] [--enabled\|--no-enabled] [--catch-up\|--no-catch-up]` | Update an agent (only the passed fields change). |
|
|
140
|
-
| `agents assign <id> [--project <id\|key>…] [--group <id\|name>…]` | Assign the agent to projects/groups (replaces targets). |
|
|
141
|
-
| `agents delete <id> --confirm` | Delete an agent and its run history. |
|
|
142
|
-
| `agents runs list <agent-id> [--page]` | List an agent's run history. |
|
|
143
|
-
| `agents runs show <agent-id> <run-id>` | Show a single run (with output). |
|
|
144
136
|
| `agents tokens list [--page]` | List the org automator tokens (cyi_a_). |
|
|
145
137
|
| `agents tokens create <name>` | Create an org automator token (secret shown only once). |
|
|
146
138
|
| `agents tokens revoke <id> --confirm` | Revoke an org automator token. |
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base';
|
|
2
|
+
export default class GuidanceShow extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
7
|
+
};
|
|
8
|
+
run(): Promise<unknown>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const base_1 = require("../../base");
|
|
4
|
+
const guidance_1 = require("../../lib/guidance");
|
|
5
|
+
class GuidanceShow extends base_1.BaseCommand {
|
|
6
|
+
static description = "Show a project's effective guidance: the references and procedures resolved by the backend (the CLI never recomposes inheritance)";
|
|
7
|
+
static examples = [
|
|
8
|
+
'<%= config.bin %> guidance show --project legalbloom-rails',
|
|
9
|
+
'<%= config.bin %> guidance show -p LBRA',
|
|
10
|
+
'<%= config.bin %> guidance show -p LBRA --json',
|
|
11
|
+
];
|
|
12
|
+
static flags = { ...base_1.projectFlag };
|
|
13
|
+
async run() {
|
|
14
|
+
const { flags } = await this.parse(GuidanceShow);
|
|
15
|
+
const projectId = await this.resolveProjectId(flags.project);
|
|
16
|
+
// The backend hands back the already-resolved guidance ({references, procedures}); the CLI only
|
|
17
|
+
// renders it. JSON stays the raw backend payload, so machine consumers get the full contract.
|
|
18
|
+
const res = await this.api.get(`/cli/v1/projects/${projectId}/guidance`);
|
|
19
|
+
if (!this.jsonEnabled()) {
|
|
20
|
+
const rendered = (0, guidance_1.renderGuidance)(res.data ?? {});
|
|
21
|
+
this.log(rendered || 'No guidance configured for this project.');
|
|
22
|
+
}
|
|
23
|
+
return res;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.default = GuidanceShow;
|
package/dist/commands/kb/show.js
CHANGED
|
@@ -46,6 +46,12 @@ class KbShow extends base_1.BaseCommand {
|
|
|
46
46
|
this.log('');
|
|
47
47
|
this.log((0, output_1.sanitizeMultiline)(body));
|
|
48
48
|
}
|
|
49
|
+
// Technical section (kept separate from the simple body), shown after it under its own heading.
|
|
50
|
+
const techSpec = page.tech_spec;
|
|
51
|
+
if (techSpec !== null && techSpec !== undefined && String(techSpec).trim() !== '') {
|
|
52
|
+
this.log('\n🔧 Technical:');
|
|
53
|
+
this.log((0, output_1.sanitizeMultiline)(techSpec));
|
|
54
|
+
}
|
|
49
55
|
const related = (res.meta?.related ?? []);
|
|
50
56
|
if (related.length > 0)
|
|
51
57
|
this.log((0, knowledge_1.renderRelated)(related));
|
|
@@ -26,6 +26,7 @@ class ProjectsGithub extends base_1.BaseCommand {
|
|
|
26
26
|
full_name: repo.full_name,
|
|
27
27
|
default_branch: repo.default_branch,
|
|
28
28
|
sync_enabled: repo.sync_enabled,
|
|
29
|
+
sync_secrets: repo.sync_secrets,
|
|
29
30
|
tag_binding_enabled: repo.tag_binding_enabled,
|
|
30
31
|
autoclose_on_merge: repo.autoclose_on_merge,
|
|
31
32
|
production_environment_id: repo.production_environment_id,
|
|
@@ -6,4 +6,11 @@ export default class ProjectsShow extends BaseCommand {
|
|
|
6
6
|
id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
7
|
};
|
|
8
8
|
run(): Promise<unknown>;
|
|
9
|
+
/**
|
|
10
|
+
* The declared environments and the capabilities (servers/uptime/secrets) active on each, so the
|
|
11
|
+
* current set can be read before `set-environments` replaces it wholesale (CYCL-4). An absent
|
|
12
|
+
* `environments` field (older backend that doesn't ship it) prints nothing, leaving `projects
|
|
13
|
+
* show` output unchanged; an empty array prints the explicit "none declared" line.
|
|
14
|
+
*/
|
|
15
|
+
private renderEnvironments;
|
|
9
16
|
}
|
|
@@ -4,7 +4,7 @@ const core_1 = require("@oclif/core");
|
|
|
4
4
|
const base_1 = require("../../base");
|
|
5
5
|
const output_1 = require("../../lib/output");
|
|
6
6
|
class ProjectsShow extends base_1.BaseCommand {
|
|
7
|
-
static description = 'Show a single project by id or key';
|
|
7
|
+
static description = 'Show a single project by id or key, with its declared environments and their capabilities';
|
|
8
8
|
static examples = ['<%= config.bin %> projects show acme-api', '<%= config.bin %> projects show <uuid> --json'];
|
|
9
9
|
static args = {
|
|
10
10
|
id: core_1.Args.string({ description: 'Project id (UUID) or key', required: true }),
|
|
@@ -14,9 +14,44 @@ class ProjectsShow extends base_1.BaseCommand {
|
|
|
14
14
|
const projectId = await this.resolveProjectId(args.id);
|
|
15
15
|
const res = await this.api.get(`/cli/v1/projects/${projectId}`);
|
|
16
16
|
if (!this.jsonEnabled()) {
|
|
17
|
-
|
|
17
|
+
const data = res.data ?? {};
|
|
18
|
+
// renderRecord prints only scalar fields, so the `environments` array is skipped here and
|
|
19
|
+
// rendered as its own table below — the project record stays exactly as before.
|
|
20
|
+
this.log((0, output_1.renderRecord)(data));
|
|
21
|
+
this.renderEnvironments(data.environments);
|
|
18
22
|
}
|
|
19
23
|
return res;
|
|
20
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* The declared environments and the capabilities (servers/uptime/secrets) active on each, so the
|
|
27
|
+
* current set can be read before `set-environments` replaces it wholesale (CYCL-4). An absent
|
|
28
|
+
* `environments` field (older backend that doesn't ship it) prints nothing, leaving `projects
|
|
29
|
+
* show` output unchanged; an empty array prints the explicit "none declared" line.
|
|
30
|
+
*/
|
|
31
|
+
renderEnvironments(value) {
|
|
32
|
+
if (!Array.isArray(value))
|
|
33
|
+
return;
|
|
34
|
+
this.log('');
|
|
35
|
+
if (value.length === 0) {
|
|
36
|
+
this.log('Environments: none declared');
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
this.log('Environments:');
|
|
40
|
+
this.log((0, output_1.renderTable)(['CODE', 'LABEL', 'SERVERS', 'UPTIME', 'SECRETS'], value.map((env) => [
|
|
41
|
+
String(env.code ?? ''),
|
|
42
|
+
String(env.label ?? ''),
|
|
43
|
+
capability(env.servers_enabled),
|
|
44
|
+
capability(env.uptime_enabled),
|
|
45
|
+
capability(env.secrets_enabled),
|
|
46
|
+
])));
|
|
47
|
+
}
|
|
21
48
|
}
|
|
22
49
|
exports.default = ProjectsShow;
|
|
50
|
+
/** A capability cell: `on`/`off` for a known boolean, `-` when the backend omits the flag. */
|
|
51
|
+
function capability(enabled) {
|
|
52
|
+
if (enabled === true)
|
|
53
|
+
return 'on';
|
|
54
|
+
if (enabled === false)
|
|
55
|
+
return 'off';
|
|
56
|
+
return '-';
|
|
57
|
+
}
|
|
@@ -4,6 +4,7 @@ export default class SecretsList extends BaseCommand {
|
|
|
4
4
|
static examples: string[];
|
|
5
5
|
static flags: {
|
|
6
6
|
environment: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
7
|
+
all: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
7
8
|
project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
8
9
|
};
|
|
9
10
|
run(): Promise<unknown>;
|
|
@@ -5,14 +5,18 @@ const base_1 = require("../../base");
|
|
|
5
5
|
const output_1 = require("../../lib/output");
|
|
6
6
|
const paginate_1 = require("../../lib/paginate");
|
|
7
7
|
class SecretsList extends base_1.BaseCommand {
|
|
8
|
-
static description = 'List secret names for a project (optionally filtered by environment).
|
|
8
|
+
static description = 'List secret names for a project (optionally filtered by environment). Lists every secret — never truncated to a page — and never prints values.';
|
|
9
9
|
static examples = [
|
|
10
10
|
'<%= config.bin %> secrets list -p acme-api',
|
|
11
11
|
'<%= config.bin %> secrets list -p acme-api -e production',
|
|
12
|
+
'<%= config.bin %> secrets list -p acme-api --all',
|
|
12
13
|
];
|
|
13
14
|
static flags = {
|
|
14
15
|
...base_1.projectFlag,
|
|
15
16
|
environment: core_1.Flags.string({ char: 'e', description: 'Filter by environment code or id' }),
|
|
17
|
+
// La lista aggrega già tutte le pagine: --all è l'affordance esplicita chiesta dal ticket
|
|
18
|
+
// (CYCL-5) per "vedere tutti i secret oltre i primi 10" senza dubbi che l'elenco sia completo.
|
|
19
|
+
all: core_1.Flags.boolean({ char: 'a', description: 'List every secret across all pages (already the default; makes the intent explicit)' }),
|
|
16
20
|
};
|
|
17
21
|
async run() {
|
|
18
22
|
const { flags } = await this.parse(SecretsList);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
4
|
const base_1 = require("../../base");
|
|
5
|
+
const guidance_1 = require("../../lib/guidance");
|
|
5
6
|
const output_1 = require("../../lib/output");
|
|
6
7
|
class TicketsShow extends base_1.BaseCommand {
|
|
7
8
|
static description = 'Show a single ticket in full: body (description + Given/When/Then/Expected), comments (with their files) and attachments';
|
|
@@ -101,6 +102,11 @@ class TicketsShow extends base_1.BaseCommand {
|
|
|
101
102
|
}
|
|
102
103
|
this.renderScenarios(Array.isArray(ticket.scenarios) ? ticket.scenarios : []);
|
|
103
104
|
this.renderConditions(Array.isArray(ticket.conditions) ? ticket.conditions : []);
|
|
105
|
+
// Effective guidance (references/procedures) when the backend ships it. Absent on older servers:
|
|
106
|
+
// renderGuidance returns '' and nothing prints, so no misleading empty section (CYCL-2).
|
|
107
|
+
const guidance = (0, guidance_1.renderGuidance)(ticket.guidance);
|
|
108
|
+
if (guidance)
|
|
109
|
+
this.log(guidance);
|
|
104
110
|
}
|
|
105
111
|
// BDD scenarios: one block per scenario, only the steps present.
|
|
106
112
|
renderScenarios(scenarios) {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One effective guidance entry (a reference or a procedure) as resolved and returned by the
|
|
3
|
+
* backend. The CLI never recomposes inheritance (CYCL-2): the hierarchy is computed server-side
|
|
4
|
+
* and every attribute below is rendered as-is — `key`, `origin`, `level`, `required` and
|
|
5
|
+
* `application_mode` are preserved verbatim.
|
|
6
|
+
*/
|
|
7
|
+
export interface GuidanceEntry extends Record<string, unknown> {
|
|
8
|
+
key?: string;
|
|
9
|
+
origin?: string;
|
|
10
|
+
level?: string;
|
|
11
|
+
required?: boolean;
|
|
12
|
+
application_mode?: string;
|
|
13
|
+
}
|
|
14
|
+
/** The effective guidance of a project: two independent, already-resolved lists. */
|
|
15
|
+
export interface Guidance extends Record<string, unknown> {
|
|
16
|
+
references?: GuidanceEntry[];
|
|
17
|
+
procedures?: GuidanceEntry[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Render the effective project guidance shared by `tickets show` and `guidance show`: references
|
|
21
|
+
* first, then procedures, each skipped when empty. Returns '' when there is nothing to show, so
|
|
22
|
+
* callers can print it unconditionally without a misleading section on servers where guidance is
|
|
23
|
+
* absent (CYCL-2).
|
|
24
|
+
*/
|
|
25
|
+
export declare function renderGuidance(guidance: unknown): string;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderGuidance = renderGuidance;
|
|
4
|
+
const output_1 = require("./output");
|
|
5
|
+
const HEADERS = ['KEY', 'ORIGIN', 'LEVEL', 'REQUIRED', 'APPLICATION_MODE'];
|
|
6
|
+
/** A `required` flag → a human yes/no; a missing value stays '-' so the column never collapses. */
|
|
7
|
+
function requiredCell(value) {
|
|
8
|
+
if (value === undefined || value === null)
|
|
9
|
+
return '-';
|
|
10
|
+
return value ? 'yes' : 'no';
|
|
11
|
+
}
|
|
12
|
+
/** One entry → a table row, in the fixed order of `HEADERS` (renderTable sanitizes each cell). */
|
|
13
|
+
function entryRow(entry) {
|
|
14
|
+
return [
|
|
15
|
+
String(entry.key ?? ''),
|
|
16
|
+
String(entry.origin ?? ''),
|
|
17
|
+
String(entry.level ?? ''),
|
|
18
|
+
requiredCell(entry.required),
|
|
19
|
+
String(entry.application_mode ?? ''),
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
/** Coerce whatever the backend sent for a list into a clean array of entries. */
|
|
23
|
+
function entries(value) {
|
|
24
|
+
return Array.isArray(value) ? value : [];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Render one titled block (References/Procedures) as a table, or '' when the list is empty — so an
|
|
28
|
+
* absent section prints nothing instead of a misleading empty header (CYCL-2, scenario 3).
|
|
29
|
+
*/
|
|
30
|
+
function renderList(title, icon, list) {
|
|
31
|
+
if (list.length === 0)
|
|
32
|
+
return '';
|
|
33
|
+
return `${(0, output_1.section)(`${title} (${list.length})`, icon)}\n${(0, output_1.renderTable)(HEADERS, list.map(entryRow))}`;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Render the effective project guidance shared by `tickets show` and `guidance show`: references
|
|
37
|
+
* first, then procedures, each skipped when empty. Returns '' when there is nothing to show, so
|
|
38
|
+
* callers can print it unconditionally without a misleading section on servers where guidance is
|
|
39
|
+
* absent (CYCL-2).
|
|
40
|
+
*/
|
|
41
|
+
function renderGuidance(guidance) {
|
|
42
|
+
if (!guidance || typeof guidance !== 'object')
|
|
43
|
+
return '';
|
|
44
|
+
const value = guidance;
|
|
45
|
+
return [
|
|
46
|
+
renderList('References', '📚', entries(value.references)),
|
|
47
|
+
renderList('Procedures', '🧭', entries(value.procedures)),
|
|
48
|
+
]
|
|
49
|
+
.filter((block) => block.length > 0)
|
|
50
|
+
.join('\n');
|
|
51
|
+
}
|