@claude-flow/cli 3.25.6 → 3.26.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/.claude/.proven-config-version +1 -0
- package/.claude/helpers/.helpers-version +1 -1
- package/.claude/helpers/helpers.manifest.json +5 -4
- package/.claude/helpers/hook-handler.cjs +129 -0
- package/.claude/helpers/statusline.cjs +771 -505
- package/.claude/proven-config.json +42 -0
- package/catalog-manifest.json +12 -0
- package/dist/src/commands/advisor.d.ts +15 -0
- package/dist/src/commands/advisor.js +94 -0
- package/dist/src/commands/doctor.js +77 -3
- package/dist/src/commands/funnel.d.ts +13 -0
- package/dist/src/commands/funnel.js +103 -0
- package/dist/src/commands/hooks.js +112 -46
- package/dist/src/commands/index.js +10 -0
- package/dist/src/commands/init.js +44 -0
- package/dist/src/commands/proxy.d.ts +21 -0
- package/dist/src/commands/proxy.js +310 -0
- package/dist/src/commands/security.js +29 -0
- package/dist/src/commands/settings.d.ts +19 -0
- package/dist/src/commands/settings.js +180 -0
- package/dist/src/commands/version.d.ts +42 -0
- package/dist/src/commands/version.js +106 -0
- package/dist/src/funnel/advisor-tip.d.ts +58 -0
- package/dist/src/funnel/advisor-tip.js +92 -0
- package/dist/src/funnel/attribution.d.ts +37 -0
- package/dist/src/funnel/attribution.js +101 -0
- package/dist/src/funnel/consent.d.ts +22 -0
- package/dist/src/funnel/consent.js +55 -0
- package/dist/src/funnel/credit-errors.d.ts +31 -0
- package/dist/src/funnel/credit-errors.js +88 -0
- package/dist/src/funnel/credit-notifier.d.ts +44 -0
- package/dist/src/funnel/credit-notifier.js +74 -0
- package/dist/src/funnel/disclosure.d.ts +46 -0
- package/dist/src/funnel/disclosure.js +97 -0
- package/dist/src/funnel/enrollment.d.ts +36 -0
- package/dist/src/funnel/enrollment.js +64 -0
- package/dist/src/funnel/environment.d.ts +17 -0
- package/dist/src/funnel/environment.js +39 -0
- package/dist/src/funnel/event-transport.d.ts +51 -0
- package/dist/src/funnel/event-transport.js +199 -0
- package/dist/src/funnel/events.d.ts +42 -0
- package/dist/src/funnel/events.js +150 -0
- package/dist/src/funnel/index.d.ts +20 -0
- package/dist/src/funnel/index.js +20 -0
- package/dist/src/funnel/insights.d.ts +49 -0
- package/dist/src/funnel/insights.js +120 -0
- package/dist/src/funnel/local-signals.d.ts +15 -0
- package/dist/src/funnel/local-signals.js +68 -0
- package/dist/src/funnel/message-transport.d.ts +51 -0
- package/dist/src/funnel/message-transport.js +149 -0
- package/dist/src/funnel/messages.d.ts +55 -0
- package/dist/src/funnel/messages.js +160 -0
- package/dist/src/funnel/power-saver-notifier.d.ts +44 -0
- package/dist/src/funnel/power-saver-notifier.js +92 -0
- package/dist/src/funnel/precedence.d.ts +16 -0
- package/dist/src/funnel/precedence.js +85 -0
- package/dist/src/funnel/promo.d.ts +41 -0
- package/dist/src/funnel/promo.js +144 -0
- package/dist/src/funnel/rate-limit-notifier.d.ts +55 -0
- package/dist/src/funnel/rate-limit-notifier.js +102 -0
- package/dist/src/funnel/rotation.d.ts +19 -0
- package/dist/src/funnel/rotation.js +70 -0
- package/dist/src/funnel/state.d.ts +13 -0
- package/dist/src/funnel/state.js +52 -0
- package/dist/src/funnel/toggle-cooldown.d.ts +17 -0
- package/dist/src/funnel/toggle-cooldown.js +32 -0
- package/dist/src/funnel/types.d.ts +86 -0
- package/dist/src/funnel/types.js +26 -0
- package/dist/src/init/executor.js +9 -3
- package/dist/src/init/helper-refresh.d.ts +33 -2
- package/dist/src/init/helper-refresh.js +102 -12
- package/dist/src/init/helpers-generator.js +52 -0
- package/dist/src/init/statusline-generator.js +282 -116
- package/dist/src/services/daemon-autostart.js +28 -5
- package/dist/src/services/fable-harness.d.ts +39 -0
- package/dist/src/services/fable-harness.js +41 -0
- package/package.json +13 -4
- package/dist/src/ruvector/lattice-wasm.d.ts +0 -14
- package/dist/src/ruvector/lattice-wasm.js +0 -144
- package/plugins/ruflo-metaharness/.claude-flow/daemon-state.json +0 -178
- package/plugins/ruflo-metaharness/.claude-flow/daemon.pid +0 -1
- package/plugins/ruflo-metaharness/.claude-flow/data/pending-insights.jsonl +0 -5
- package/plugins/ruflo-metaharness/.claude-flow/logs/daemon.log +0 -43
- package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783604774864_ozbujc_prompt.log +0 -19
- package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783604774864_ozbujc_result.log +0 -108
- package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783605513587_ulvmpb_prompt.log +0 -19
- package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783605513587_ulvmpb_result.log +0 -209
- package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783606368867_ahysui_prompt.log +0 -19
- package/plugins/ruflo-metaharness/.claude-flow/logs/headless/audit_1783606368867_ahysui_result.log +0 -192
- package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783604894861_v6n3ut_prompt.log +0 -14
- package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783604894861_v6n3ut_result.log +0 -66
- package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783605934532_9h8ikb_prompt.log +0 -14
- package/plugins/ruflo-metaharness/.claude-flow/logs/headless/optimize_1783605934532_9h8ikb_result.log +0 -68
- package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783605134860_9jssz9_prompt.log +0 -14
- package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783605134860_9jssz9_result.log +0 -69
- package/plugins/ruflo-metaharness/.claude-flow/logs/headless/testgaps_1783606516743_zftbaa_prompt.log +0 -14
- package/plugins/ruflo-metaharness/.claude-flow/metrics/backup.json +0 -7
- package/plugins/ruflo-metaharness/.claude-flow/metrics/codebase-map.json +0 -11
- package/plugins/ruflo-metaharness/.claude-flow/metrics/consolidation.json +0 -16
- package/plugins/ruflo-metaharness/.claude-flow/metrics/harness-loop.json +0 -83
- package/plugins/ruflo-metaharness/.claude-flow/metrics/performance.json +0 -67
- package/plugins/ruflo-metaharness/.claude-flow/metrics/security-audit.json +0 -191
- package/plugins/ruflo-metaharness/.claude-flow/metrics/test-gaps.json +0 -68
- package/plugins/ruflo-metaharness/.claude-flow/neural/stats.json +0 -6
|
@@ -7,6 +7,41 @@ import { confirm, select, multiSelect, input } from '../prompt.js';
|
|
|
7
7
|
import * as fs from 'fs';
|
|
8
8
|
import * as path from 'path';
|
|
9
9
|
import { executeInit, executeUpgrade, executeUpgradeWithMissing, DEFAULT_INIT_OPTIONS, MINIMAL_INIT_OPTIONS, FULL_INIT_OPTIONS, } from '../init/index.js';
|
|
10
|
+
import { ENROLLMENT_SCREEN, recordEnrollmentOutcome, shouldOfferEnrollment, } from '../funnel/enrollment.js';
|
|
11
|
+
/**
|
|
12
|
+
* ADR-302 post-init capability enrollment. One-time, interactive-TTY-only,
|
|
13
|
+
* skippable with --no-signup, auto-skipped in CI/automation. Never throws
|
|
14
|
+
* and never affects init's exit code. Accepting records the `account`
|
|
15
|
+
* consent receipt only — no other capability is enabled by this prompt.
|
|
16
|
+
*/
|
|
17
|
+
async function offerCapabilityEnrollment(ctx) {
|
|
18
|
+
try {
|
|
19
|
+
const noSignup = Boolean(ctx.flags['no-signup'] || ctx.flags.noSignup);
|
|
20
|
+
if (ctx.flags.format === 'json')
|
|
21
|
+
return; // scripted output stays pure
|
|
22
|
+
if (!shouldOfferEnrollment({ noSignup, cwd: ctx.cwd }))
|
|
23
|
+
return;
|
|
24
|
+
output.writeln();
|
|
25
|
+
output.writeln(ENROLLMENT_SCREEN);
|
|
26
|
+
output.writeln();
|
|
27
|
+
const accepted = await confirm({
|
|
28
|
+
message: 'Create a free Cognitum account now?',
|
|
29
|
+
default: false,
|
|
30
|
+
});
|
|
31
|
+
recordEnrollmentOutcome(Boolean(accepted));
|
|
32
|
+
output.writeln();
|
|
33
|
+
if (accepted) {
|
|
34
|
+
output.printInfo('Create your free account at https://cognitum.one');
|
|
35
|
+
output.writeln(output.dim(' CLI sign-in (`ruflo auth login`) ships with the ADR-306 auth release.'));
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
output.writeln(output.dim('You can enable later at https://cognitum.one — this prompt will not repeat.'));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Enrollment is optional; init success is never affected.
|
|
43
|
+
}
|
|
44
|
+
}
|
|
10
45
|
// Codex initialization action
|
|
11
46
|
async function initCodexAction(ctx, options) {
|
|
12
47
|
const { force, minimal, full, dualMode } = options;
|
|
@@ -445,6 +480,7 @@ const initAction = async (ctx) => {
|
|
|
445
480
|
if (ctx.flags.format === 'json') {
|
|
446
481
|
output.printJson(result);
|
|
447
482
|
}
|
|
483
|
+
await offerCapabilityEnrollment(ctx);
|
|
448
484
|
return { success: true, data: result };
|
|
449
485
|
}
|
|
450
486
|
catch (error) {
|
|
@@ -686,6 +722,7 @@ const wizardCommand = {
|
|
|
686
722
|
{ setting: 'Hooks', value: `${result.summary.hooksEnabled} enabled` },
|
|
687
723
|
],
|
|
688
724
|
});
|
|
725
|
+
await offerCapabilityEnrollment(ctx);
|
|
689
726
|
return { success: true, data: result };
|
|
690
727
|
}
|
|
691
728
|
catch (error) {
|
|
@@ -1017,6 +1054,13 @@ export const initCommand = {
|
|
|
1017
1054
|
type: 'boolean',
|
|
1018
1055
|
default: false,
|
|
1019
1056
|
},
|
|
1057
|
+
{
|
|
1058
|
+
// ADR-302 — skip the one-time post-init capability enrollment prompt.
|
|
1059
|
+
name: 'no-signup',
|
|
1060
|
+
description: 'Skip the post-init Cognitum capability enrollment prompt',
|
|
1061
|
+
type: 'boolean',
|
|
1062
|
+
default: false,
|
|
1063
|
+
},
|
|
1020
1064
|
{
|
|
1021
1065
|
name: 'only-claude',
|
|
1022
1066
|
description: 'Only create .claude/ directory (skip runtime)',
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ruflo proxy` — Meta LLM Proxy control surface (ADR-304/307/313).
|
|
3
|
+
*
|
|
4
|
+
* This command currently implements the ADR-313 sponsored-downtime
|
|
5
|
+
* subcommands only (`sponsor-enable` / `sponsor-disable` / `sponsor-status`).
|
|
6
|
+
* The full lifecycle command set ADR-307 specifies
|
|
7
|
+
* (`install|start|stop|status|logs|update|uninstall`) manages the proxy
|
|
8
|
+
* *process* itself and is out of scope here — this surface only manages
|
|
9
|
+
* the consent-gated sponsored-mode flag the already-running proxy reads
|
|
10
|
+
* from its config mirror.
|
|
11
|
+
*
|
|
12
|
+
* Consent (ADR-302/313): granting `sponsored-downtime` consent here writes
|
|
13
|
+
* BOTH the ruflo-side consent receipt (source of truth) AND a mirror flag
|
|
14
|
+
* into ~/.ruflo/proxy-config.toml (the file the Rust proxy binary reads).
|
|
15
|
+
* The proxy never writes this file — ruflo does, exactly once per
|
|
16
|
+
* enable/disable action.
|
|
17
|
+
*/
|
|
18
|
+
import type { Command } from '../types.js';
|
|
19
|
+
export declare const proxyCommand: Command;
|
|
20
|
+
export default proxyCommand;
|
|
21
|
+
//# sourceMappingURL=proxy.d.ts.map
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ruflo proxy` — Meta LLM Proxy control surface (ADR-304/307/313).
|
|
3
|
+
*
|
|
4
|
+
* This command currently implements the ADR-313 sponsored-downtime
|
|
5
|
+
* subcommands only (`sponsor-enable` / `sponsor-disable` / `sponsor-status`).
|
|
6
|
+
* The full lifecycle command set ADR-307 specifies
|
|
7
|
+
* (`install|start|stop|status|logs|update|uninstall`) manages the proxy
|
|
8
|
+
* *process* itself and is out of scope here — this surface only manages
|
|
9
|
+
* the consent-gated sponsored-mode flag the already-running proxy reads
|
|
10
|
+
* from its config mirror.
|
|
11
|
+
*
|
|
12
|
+
* Consent (ADR-302/313): granting `sponsored-downtime` consent here writes
|
|
13
|
+
* BOTH the ruflo-side consent receipt (source of truth) AND a mirror flag
|
|
14
|
+
* into ~/.ruflo/proxy-config.toml (the file the Rust proxy binary reads).
|
|
15
|
+
* The proxy never writes this file — ruflo does, exactly once per
|
|
16
|
+
* enable/disable action.
|
|
17
|
+
*/
|
|
18
|
+
import * as fs from 'fs';
|
|
19
|
+
import { output } from '../output.js';
|
|
20
|
+
import { hasConsent, recordConsent, revokeConsent, funnelStateDir } from '../funnel/index.js';
|
|
21
|
+
import { recordFunnelEvent } from '../funnel/events.js';
|
|
22
|
+
import { clearRateLimitStatus, readRateLimitStatus } from '../funnel/rate-limit-notifier.js';
|
|
23
|
+
import { clearQuotaLowStatus, readQuotaLowStatus } from '../funnel/power-saver-notifier.js';
|
|
24
|
+
import { getInstalledCliVersion } from '../init/helper-refresh.js';
|
|
25
|
+
import * as path from 'path';
|
|
26
|
+
const PROXY_CONFIG_FILE = 'proxy-config.toml';
|
|
27
|
+
/**
|
|
28
|
+
* Minimal hand-rolled TOML writer — this config has exactly one boolean
|
|
29
|
+
* field ruflo needs to set (`sponsored_consent_granted`); every other field
|
|
30
|
+
* the proxy binary defaults itself (ADR-307 "a malformed config must never
|
|
31
|
+
* crash the proxy — it degrades to safe defaults"). We read-modify-write
|
|
32
|
+
* the raw text so a user's own bind/backend customizations survive, only
|
|
33
|
+
* ever touching this one line. No TOML parser dependency needed for this.
|
|
34
|
+
*/
|
|
35
|
+
function readProxyConfigRaw() {
|
|
36
|
+
try {
|
|
37
|
+
return fs.readFileSync(path.join(funnelStateDir(), PROXY_CONFIG_FILE), 'utf-8');
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return '';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function writeConsentMirrorLine(field, value) {
|
|
44
|
+
const dir = funnelStateDir();
|
|
45
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
46
|
+
const target = path.join(dir, PROXY_CONFIG_FILE);
|
|
47
|
+
const raw = readProxyConfigRaw();
|
|
48
|
+
const line = `${field} = ${value}`;
|
|
49
|
+
const pattern = new RegExp(`^${field}\\s*=.*$`, 'm');
|
|
50
|
+
let next;
|
|
51
|
+
if (pattern.test(raw)) {
|
|
52
|
+
next = raw.replace(pattern, line);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
next = raw.length > 0 ? `${raw.trimEnd()}\n${line}\n` : `${line}\n`;
|
|
56
|
+
}
|
|
57
|
+
const tmp = `${target}.tmp`;
|
|
58
|
+
fs.writeFileSync(tmp, next, { encoding: 'utf-8', mode: 0o600 });
|
|
59
|
+
fs.renameSync(tmp, target);
|
|
60
|
+
}
|
|
61
|
+
function writeSponsoredConsentMirror(granted) {
|
|
62
|
+
writeConsentMirrorLine('sponsored_consent_granted', granted);
|
|
63
|
+
}
|
|
64
|
+
function writePowerSaverConsentMirror(granted) {
|
|
65
|
+
writeConsentMirrorLine('power_saver_consent_granted', granted);
|
|
66
|
+
}
|
|
67
|
+
function writeTrainingShareConsentMirror(granted) {
|
|
68
|
+
writeConsentMirrorLine('training_share_consent_granted', granted);
|
|
69
|
+
}
|
|
70
|
+
const SPONSOR_DISCLOSURE = [
|
|
71
|
+
'Enabling sponsored downtime mode.',
|
|
72
|
+
'',
|
|
73
|
+
"While your Claude usage limit resets, requests can be routed through",
|
|
74
|
+
"Cognitum's own model capacity, sponsored at no cost to you. This is a",
|
|
75
|
+
'separate data plane from your own cloud-routing config — Cognitum sees',
|
|
76
|
+
'these prompts (server-side, same handling as any api.cognitum.one',
|
|
77
|
+
'request), never your own Claude account.',
|
|
78
|
+
'',
|
|
79
|
+
'Sponsored capacity is rate-limited and best-effort — Cognitum may',
|
|
80
|
+
'throttle or decline requests under load. Disable anytime:',
|
|
81
|
+
' ruflo proxy sponsor-disable',
|
|
82
|
+
].join('\n');
|
|
83
|
+
const sponsorEnableSub = {
|
|
84
|
+
name: 'sponsor-enable',
|
|
85
|
+
description: "Opt into Cognitum-sponsored downtime capacity (ADR-313)",
|
|
86
|
+
options: [
|
|
87
|
+
{ name: 'yes', description: 'Skip the confirmation prompt', type: 'boolean', default: false },
|
|
88
|
+
],
|
|
89
|
+
action: async (ctx) => {
|
|
90
|
+
if (hasConsent('sponsored-downtime')) {
|
|
91
|
+
output.writeln('Sponsored downtime mode is already enabled.');
|
|
92
|
+
return { success: true, data: { alreadyEnabled: true } };
|
|
93
|
+
}
|
|
94
|
+
output.writeln(SPONSOR_DISCLOSURE);
|
|
95
|
+
output.writeln('');
|
|
96
|
+
if (!ctx.flags.yes) {
|
|
97
|
+
output.writeln('Re-run with --yes to confirm: ruflo proxy sponsor-enable --yes');
|
|
98
|
+
return { success: true, data: { confirmed: false } };
|
|
99
|
+
}
|
|
100
|
+
recordConsent('sponsored-downtime', true, 'proxy-sponsor-enable');
|
|
101
|
+
writeSponsoredConsentMirror(true);
|
|
102
|
+
recordFunnelEvent('sponsor_mode_enabled', 'statusline', getInstalledCliVersion());
|
|
103
|
+
output.printSuccess('Sponsored downtime mode enabled.');
|
|
104
|
+
output.writeln('The proxy will use it automatically while ruflo settings notices');
|
|
105
|
+
output.writeln('rate-limited is flagged. Disable anytime: ruflo proxy sponsor-disable');
|
|
106
|
+
return { success: true, data: { confirmed: true } };
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
const sponsorDisableSub = {
|
|
110
|
+
name: 'sponsor-disable',
|
|
111
|
+
description: 'Revoke sponsored-downtime consent and stop using sponsored capacity',
|
|
112
|
+
action: async () => {
|
|
113
|
+
revokeConsent('sponsored-downtime', 'proxy-sponsor-disable');
|
|
114
|
+
writeSponsoredConsentMirror(false);
|
|
115
|
+
recordFunnelEvent('sponsor_mode_disabled', 'statusline', getInstalledCliVersion());
|
|
116
|
+
output.printSuccess('Sponsored downtime mode disabled.');
|
|
117
|
+
return { success: true };
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
const sponsorStatusSub = {
|
|
121
|
+
name: 'sponsor-status',
|
|
122
|
+
description: 'Show sponsored-downtime consent + rate-limit flag state',
|
|
123
|
+
action: async () => {
|
|
124
|
+
const consented = hasConsent('sponsored-downtime');
|
|
125
|
+
const rateLimited = readRateLimitStatus();
|
|
126
|
+
output.writeln(`Sponsored downtime consent: ${consented ? 'granted' : 'not granted'}`);
|
|
127
|
+
output.writeln(`Rate-limit flag: ${rateLimited.limited ? `set (since ${rateLimited.since})` : 'not set'}`);
|
|
128
|
+
if (rateLimited.limited && !consented) {
|
|
129
|
+
output.writeln('');
|
|
130
|
+
output.writeln('You are flagged as rate-limited but have not enabled sponsored');
|
|
131
|
+
output.writeln('capacity. Enable it with: ruflo proxy sponsor-enable --yes');
|
|
132
|
+
}
|
|
133
|
+
return { success: true, data: { consented, rateLimited } };
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
/** Convenience: clear the rate-limited flag once you're back to normal. */
|
|
137
|
+
const sponsorClearSub = {
|
|
138
|
+
name: 'sponsor-clear',
|
|
139
|
+
description: 'Clear the rate-limited flag (your Claude limit has reset)',
|
|
140
|
+
action: async () => {
|
|
141
|
+
const changed = clearRateLimitStatus();
|
|
142
|
+
if (!changed) {
|
|
143
|
+
output.printError('Rate-limit flag was just toggled — try again in a few minutes (ADR-314 anti-abuse cooldown).');
|
|
144
|
+
return { success: false };
|
|
145
|
+
}
|
|
146
|
+
output.printSuccess('Rate-limit flag cleared.');
|
|
147
|
+
return { success: true };
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
const POWER_SAVER_DISCLOSURE = [
|
|
151
|
+
'Enabling power saver mode.',
|
|
152
|
+
'',
|
|
153
|
+
"Everyday requests will route through Cognitum's own difficulty-based",
|
|
154
|
+
'router (cognitum-auto) instead of your Claude subscription directly —',
|
|
155
|
+
'simple messages stay cheap, genuinely hard reasoning still escalates to',
|
|
156
|
+
'a comparable frontier model. This is billed to YOUR OWN Cognitum',
|
|
157
|
+
'account (cloud-routing), not sponsored/free capacity — a separate',
|
|
158
|
+
'decision from sponsored downtime mode.',
|
|
159
|
+
'',
|
|
160
|
+
'Disable anytime: ruflo proxy power-saver-disable',
|
|
161
|
+
].join('\n');
|
|
162
|
+
const powerSaverEnableSub = {
|
|
163
|
+
name: 'power-saver-enable',
|
|
164
|
+
description: 'Opt into power saver mode — route everyday requests through your own Cognitum account (ADR-314)',
|
|
165
|
+
options: [
|
|
166
|
+
{ name: 'yes', description: 'Skip the confirmation prompt', type: 'boolean', default: false },
|
|
167
|
+
],
|
|
168
|
+
action: async (ctx) => {
|
|
169
|
+
if (hasConsent('power-saver')) {
|
|
170
|
+
output.writeln('Power saver mode is already enabled.');
|
|
171
|
+
return { success: true, data: { alreadyEnabled: true } };
|
|
172
|
+
}
|
|
173
|
+
output.writeln(POWER_SAVER_DISCLOSURE);
|
|
174
|
+
output.writeln('');
|
|
175
|
+
if (!ctx.flags.yes) {
|
|
176
|
+
output.writeln('Re-run with --yes to confirm: ruflo proxy power-saver-enable --yes');
|
|
177
|
+
return { success: true, data: { confirmed: false } };
|
|
178
|
+
}
|
|
179
|
+
recordConsent('power-saver', true, 'proxy-power-saver-enable');
|
|
180
|
+
writePowerSaverConsentMirror(true);
|
|
181
|
+
recordFunnelEvent('power_saver_enabled', 'statusline', getInstalledCliVersion());
|
|
182
|
+
output.printSuccess('Power saver mode enabled.');
|
|
183
|
+
output.writeln('Flag it active with: ruflo settings notices quota-low');
|
|
184
|
+
output.writeln('Disable anytime: ruflo proxy power-saver-disable');
|
|
185
|
+
return { success: true, data: { confirmed: true } };
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
const powerSaverDisableSub = {
|
|
189
|
+
name: 'power-saver-disable',
|
|
190
|
+
description: 'Revoke power-saver consent and stop routing through Cognitum for cost savings',
|
|
191
|
+
action: async () => {
|
|
192
|
+
revokeConsent('power-saver', 'proxy-power-saver-disable');
|
|
193
|
+
writePowerSaverConsentMirror(false);
|
|
194
|
+
recordFunnelEvent('power_saver_disabled', 'statusline', getInstalledCliVersion());
|
|
195
|
+
output.printSuccess('Power saver mode disabled.');
|
|
196
|
+
return { success: true };
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
const powerSaverStatusSub = {
|
|
200
|
+
name: 'power-saver-status',
|
|
201
|
+
description: 'Show power-saver consent + quota-low flag state',
|
|
202
|
+
action: async () => {
|
|
203
|
+
const consented = hasConsent('power-saver');
|
|
204
|
+
const quotaLow = readQuotaLowStatus();
|
|
205
|
+
output.writeln(`Power saver consent: ${consented ? 'granted' : 'not granted'}`);
|
|
206
|
+
output.writeln(`Quota-low flag: ${quotaLow.low ? `set (since ${quotaLow.since})` : 'not set'}`);
|
|
207
|
+
if (quotaLow.low && !consented) {
|
|
208
|
+
output.writeln('');
|
|
209
|
+
output.writeln('You are flagged as running low but have not enabled power saver');
|
|
210
|
+
output.writeln('mode. Enable it with: ruflo proxy power-saver-enable --yes');
|
|
211
|
+
}
|
|
212
|
+
return { success: true, data: { consented, quotaLow } };
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
/** Convenience: clear the quota-low flag once you're back to normal. */
|
|
216
|
+
const powerSaverClearSub = {
|
|
217
|
+
name: 'power-saver-clear',
|
|
218
|
+
description: 'Clear the quota-low flag',
|
|
219
|
+
action: async () => {
|
|
220
|
+
const changed = clearQuotaLowStatus();
|
|
221
|
+
if (!changed) {
|
|
222
|
+
output.printError('Quota-low flag was just toggled — try again in a few minutes (ADR-314 anti-abuse cooldown).');
|
|
223
|
+
return { success: false };
|
|
224
|
+
}
|
|
225
|
+
output.printSuccess('Quota-low flag cleared.');
|
|
226
|
+
return { success: true };
|
|
227
|
+
},
|
|
228
|
+
};
|
|
229
|
+
const TRAINING_SHARE_DISCLOSURE = [
|
|
230
|
+
'Enabling training-data sharing.',
|
|
231
|
+
'',
|
|
232
|
+
'When a request runs on the sponsored plane, the proxy will attach a',
|
|
233
|
+
'consent header telling Cognitum it may retain that interaction —',
|
|
234
|
+
'(post safety-scan) — as input to its MicroLoRA training pipeline',
|
|
235
|
+
'(meta-llm ADR-251), gated through its existing SHADOW/promotion-rule',
|
|
236
|
+
'safety net; adaptations are never auto-served. This is content, not',
|
|
237
|
+
'just metadata, and is entirely separate from sponsored-downtime',
|
|
238
|
+
'consent — using free capacity never implicitly means this is on.',
|
|
239
|
+
'',
|
|
240
|
+
'Declining has zero effect on sponsored-capacity access.',
|
|
241
|
+
'',
|
|
242
|
+
'Disable anytime: ruflo proxy training-share-disable',
|
|
243
|
+
].join('\n');
|
|
244
|
+
const trainingShareEnableSub = {
|
|
245
|
+
name: 'training-share-enable',
|
|
246
|
+
description: 'Opt into sharing sponsored-plane interaction content for meta-llm training (ADR-315)',
|
|
247
|
+
options: [
|
|
248
|
+
{ name: 'yes', description: 'Skip the confirmation prompt', type: 'boolean', default: false },
|
|
249
|
+
],
|
|
250
|
+
action: async (ctx) => {
|
|
251
|
+
if (hasConsent('training-data-sharing')) {
|
|
252
|
+
output.writeln('Training-data sharing is already enabled.');
|
|
253
|
+
return { success: true, data: { alreadyEnabled: true } };
|
|
254
|
+
}
|
|
255
|
+
output.writeln(TRAINING_SHARE_DISCLOSURE);
|
|
256
|
+
output.writeln('');
|
|
257
|
+
if (!ctx.flags.yes) {
|
|
258
|
+
output.writeln('Re-run with --yes to confirm: ruflo proxy training-share-enable --yes');
|
|
259
|
+
return { success: true, data: { confirmed: false } };
|
|
260
|
+
}
|
|
261
|
+
recordConsent('training-data-sharing', true, 'proxy-training-share-enable');
|
|
262
|
+
writeTrainingShareConsentMirror(true);
|
|
263
|
+
recordFunnelEvent('training_share_enabled', 'statusline', getInstalledCliVersion());
|
|
264
|
+
output.printSuccess('Training-data sharing enabled.');
|
|
265
|
+
output.writeln('Only sponsored-plane requests carry the consent header. Disable anytime:');
|
|
266
|
+
output.writeln(' ruflo proxy training-share-disable');
|
|
267
|
+
return { success: true, data: { confirmed: true } };
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
const trainingShareDisableSub = {
|
|
271
|
+
name: 'training-share-disable',
|
|
272
|
+
description: 'Revoke training-data-sharing consent — stop sending the training consent header',
|
|
273
|
+
action: async () => {
|
|
274
|
+
revokeConsent('training-data-sharing', 'proxy-training-share-disable');
|
|
275
|
+
writeTrainingShareConsentMirror(false);
|
|
276
|
+
recordFunnelEvent('training_share_disabled', 'statusline', getInstalledCliVersion());
|
|
277
|
+
output.printSuccess('Training-data sharing disabled.');
|
|
278
|
+
return { success: true };
|
|
279
|
+
},
|
|
280
|
+
};
|
|
281
|
+
const trainingShareStatusSub = {
|
|
282
|
+
name: 'training-share-status',
|
|
283
|
+
description: 'Show training-data-sharing consent state',
|
|
284
|
+
action: async () => {
|
|
285
|
+
const consented = hasConsent('training-data-sharing');
|
|
286
|
+
output.writeln(`Training-data sharing consent: ${consented ? 'granted' : 'not granted'}`);
|
|
287
|
+
if (consented) {
|
|
288
|
+
output.writeln('Sponsored-plane requests carry X-Cognitum-Training-Consent: true.');
|
|
289
|
+
}
|
|
290
|
+
return { success: true, data: { consented } };
|
|
291
|
+
},
|
|
292
|
+
};
|
|
293
|
+
export const proxyCommand = {
|
|
294
|
+
name: 'proxy',
|
|
295
|
+
description: 'Meta LLM Proxy — sponsored downtime + power saver + training-data sharing (ADR-304/307/313/314/315)',
|
|
296
|
+
subcommands: [
|
|
297
|
+
sponsorEnableSub, sponsorDisableSub, sponsorStatusSub, sponsorClearSub,
|
|
298
|
+
powerSaverEnableSub, powerSaverDisableSub, powerSaverStatusSub, powerSaverClearSub,
|
|
299
|
+
trainingShareEnableSub, trainingShareDisableSub, trainingShareStatusSub,
|
|
300
|
+
],
|
|
301
|
+
examples: [
|
|
302
|
+
{ command: 'ruflo proxy sponsor-status', description: 'Show current sponsored-mode state' },
|
|
303
|
+
{ command: 'ruflo proxy sponsor-enable --yes', description: 'Opt into sponsored downtime capacity' },
|
|
304
|
+
{ command: 'ruflo proxy power-saver-enable --yes', description: 'Opt into power saver mode' },
|
|
305
|
+
{ command: 'ruflo proxy training-share-enable --yes', description: 'Opt into training-data sharing (ADR-315)' },
|
|
306
|
+
],
|
|
307
|
+
action: sponsorStatusSub.action,
|
|
308
|
+
};
|
|
309
|
+
export default proxyCommand;
|
|
310
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -218,6 +218,35 @@ const scanCommand = {
|
|
|
218
218
|
`Critical: ${criticalCount} High: ${highCount} Medium: ${mediumCount} Low: ${lowCount}`,
|
|
219
219
|
`Total Issues: ${findings.length}`,
|
|
220
220
|
].join('\n'), 'Scan Summary');
|
|
221
|
+
// Persist the scan result so downstream consumers (the statusline's
|
|
222
|
+
// getSecurityStatus in funnel/local-signals.ts, which reads
|
|
223
|
+
// `.claude/security-scans/*.json`) reflect real scan state. Best-effort:
|
|
224
|
+
// a failed write must never fail the scan itself.
|
|
225
|
+
try {
|
|
226
|
+
const scanDirOut = path.join(path.resolve(target), '.claude', 'security-scans');
|
|
227
|
+
fs.mkdirSync(scanDirOut, { recursive: true });
|
|
228
|
+
const record = {
|
|
229
|
+
timestamp: new Date().toISOString(),
|
|
230
|
+
target,
|
|
231
|
+
depth,
|
|
232
|
+
type: scanType,
|
|
233
|
+
summary: {
|
|
234
|
+
critical: criticalCount,
|
|
235
|
+
high: highCount,
|
|
236
|
+
medium: mediumCount,
|
|
237
|
+
low: lowCount,
|
|
238
|
+
total: findings.length,
|
|
239
|
+
},
|
|
240
|
+
findings,
|
|
241
|
+
};
|
|
242
|
+
// Deterministic name keyed on scan config so repeated runs overwrite
|
|
243
|
+
// rather than accumulate stale reports.
|
|
244
|
+
const outFile = path.join(scanDirOut, `scan-${scanType}-${depth}.json`);
|
|
245
|
+
fs.writeFileSync(outFile, JSON.stringify(record, null, 2));
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
// Persistence is advisory only — ignore write failures.
|
|
249
|
+
}
|
|
221
250
|
// Auto-fix if requested
|
|
222
251
|
if (fix && criticalCount + highCount > 0) {
|
|
223
252
|
output.writeln();
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ruflo settings` — user-facing preferences router (ADR-311 amendment).
|
|
3
|
+
*
|
|
4
|
+
* The name change from `ruflo funnel …` is deliberate copy discipline:
|
|
5
|
+
* "funnel" is internal analytics terminology; it should not appear in the
|
|
6
|
+
* command surface end users see. Every subcommand here forwards to the
|
|
7
|
+
* existing `ruflo funnel` primitives so behavior stays identical — this
|
|
8
|
+
* is a friendlier wrapper, not a re-implementation.
|
|
9
|
+
*
|
|
10
|
+
* Subcommands:
|
|
11
|
+
* ruflo settings Show effective settings + how to change them
|
|
12
|
+
* ruflo settings notices status Show whether the notices row is on
|
|
13
|
+
* ruflo settings notices off Turn off the notices row (persistent)
|
|
14
|
+
* ruflo settings notices on Re-enable the notices row
|
|
15
|
+
* ruflo settings notices id Show the pseudonymous notices id
|
|
16
|
+
*/
|
|
17
|
+
import type { Command } from '../types.js';
|
|
18
|
+
export declare const settingsCommand: Command;
|
|
19
|
+
//# sourceMappingURL=settings.d.ts.map
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ruflo settings` — user-facing preferences router (ADR-311 amendment).
|
|
3
|
+
*
|
|
4
|
+
* The name change from `ruflo funnel …` is deliberate copy discipline:
|
|
5
|
+
* "funnel" is internal analytics terminology; it should not appear in the
|
|
6
|
+
* command surface end users see. Every subcommand here forwards to the
|
|
7
|
+
* existing `ruflo funnel` primitives so behavior stays identical — this
|
|
8
|
+
* is a friendlier wrapper, not a re-implementation.
|
|
9
|
+
*
|
|
10
|
+
* Subcommands:
|
|
11
|
+
* ruflo settings Show effective settings + how to change them
|
|
12
|
+
* ruflo settings notices status Show whether the notices row is on
|
|
13
|
+
* ruflo settings notices off Turn off the notices row (persistent)
|
|
14
|
+
* ruflo settings notices on Re-enable the notices row
|
|
15
|
+
* ruflo settings notices id Show the pseudonymous notices id
|
|
16
|
+
*/
|
|
17
|
+
import { output } from '../output.js';
|
|
18
|
+
import { deleteFunnelData, funnelStateDir, getDisclosure, getFunnelId, hasConsent, readConsents, recordDisclosureDeclined, recordDisclosureReenabled, resolveFunnelEnabled, } from '../funnel/index.js';
|
|
19
|
+
import { readStateJson, writeStateJson } from '../funnel/state.js';
|
|
20
|
+
import { clearRateLimitStatus, markRateLimited, rateLimitNotice, readRateLimitStatus, } from '../funnel/rate-limit-notifier.js';
|
|
21
|
+
import { clearQuotaLowStatus, markQuotaLow, quotaLowNotice, readQuotaLowStatus, } from '../funnel/power-saver-notifier.js';
|
|
22
|
+
function setUserConfigEnabled(enabled) {
|
|
23
|
+
const cfg = readStateJson('funnel.json') ?? {};
|
|
24
|
+
cfg.enabled = enabled;
|
|
25
|
+
writeStateJson('funnel.json', cfg);
|
|
26
|
+
}
|
|
27
|
+
const noticesStatusSub = {
|
|
28
|
+
name: 'status',
|
|
29
|
+
description: 'Show whether notices are on and which source decided it',
|
|
30
|
+
action: async () => {
|
|
31
|
+
const decision = resolveFunnelEnabled();
|
|
32
|
+
const disclosure = getDisclosure();
|
|
33
|
+
output.writeln(`Notices: ${decision.enabled ? 'enabled' : 'disabled'} (decided by: ${decision.decidedBy})`);
|
|
34
|
+
output.writeln(`Disclosure: ${disclosure.state}`);
|
|
35
|
+
output.writeln(`Telemetry: ${hasConsent('telemetry') ? 'consent granted' : 'no consent'}`);
|
|
36
|
+
return { success: true, data: { decision, disclosure: disclosure.state } };
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
const noticesOffSub = {
|
|
40
|
+
name: 'off',
|
|
41
|
+
description: 'Turn off statusline notices (persistent, user-level)',
|
|
42
|
+
action: async () => {
|
|
43
|
+
setUserConfigEnabled(false);
|
|
44
|
+
recordDisclosureDeclined();
|
|
45
|
+
deleteFunnelData();
|
|
46
|
+
output.printSuccess('Notices disabled. Local notice data deleted.');
|
|
47
|
+
return { success: true };
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
const noticesOnSub = {
|
|
51
|
+
name: 'on',
|
|
52
|
+
description: 'Re-enable statusline notices',
|
|
53
|
+
action: async () => {
|
|
54
|
+
setUserConfigEnabled(true);
|
|
55
|
+
recordDisclosureReenabled();
|
|
56
|
+
const decision = resolveFunnelEnabled();
|
|
57
|
+
if (decision.enabled) {
|
|
58
|
+
output.printSuccess('Notices enabled.');
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
output.printWarning(`User preference recorded, but notices stay off (decided by: ${decision.decidedBy})`);
|
|
62
|
+
}
|
|
63
|
+
return { success: true, data: decision };
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
const noticesIdSub = {
|
|
67
|
+
name: 'id',
|
|
68
|
+
description: 'Print the pseudonymous notices ID (telemetry consent required)',
|
|
69
|
+
action: async () => {
|
|
70
|
+
const id = getFunnelId();
|
|
71
|
+
output.writeln(id ?? '(no id — telemetry consent not granted, or notices are off)');
|
|
72
|
+
return { success: true, data: { id } };
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
const rateLimitedSub = {
|
|
76
|
+
name: 'rate-limited',
|
|
77
|
+
description: 'Manually flag that you have hit a Claude usage limit (ADR-312 Phase 0)',
|
|
78
|
+
options: [
|
|
79
|
+
{ name: 'clear', description: 'Clear the flag', type: 'boolean', default: false },
|
|
80
|
+
],
|
|
81
|
+
action: async (ctx) => {
|
|
82
|
+
if (ctx.flags.clear) {
|
|
83
|
+
const changed = clearRateLimitStatus();
|
|
84
|
+
if (!changed) {
|
|
85
|
+
output.printError('Rate-limit flag was just toggled — try again in a few minutes (ADR-314 anti-abuse cooldown).');
|
|
86
|
+
return { success: false };
|
|
87
|
+
}
|
|
88
|
+
output.printSuccess('Rate-limit flag cleared.');
|
|
89
|
+
return { success: true };
|
|
90
|
+
}
|
|
91
|
+
const changed = markRateLimited();
|
|
92
|
+
if (!changed) {
|
|
93
|
+
output.printError('Rate-limit flag was just toggled — try again in a few minutes (ADR-314 anti-abuse cooldown).');
|
|
94
|
+
return { success: false };
|
|
95
|
+
}
|
|
96
|
+
output.printSuccess('Rate-limit flag set.');
|
|
97
|
+
output.writeln('');
|
|
98
|
+
output.writeln('This is a manual, self-reported flag — ruflo cannot detect Claude\'s');
|
|
99
|
+
output.writeln('usage-limit state automatically today (see ADR-312). While flagged,');
|
|
100
|
+
output.writeln('the notices row may suggest sponsored Cognitum capacity as a bridge');
|
|
101
|
+
output.writeln('until your own limit resets: ruflo proxy sponsor-enable');
|
|
102
|
+
output.writeln('');
|
|
103
|
+
output.writeln('Clear it any time: ruflo settings notices rate-limited --clear');
|
|
104
|
+
const notice = rateLimitNotice();
|
|
105
|
+
return { success: true, data: { notice, status: readRateLimitStatus() } };
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
const quotaLowSub = {
|
|
109
|
+
name: 'quota-low',
|
|
110
|
+
description: 'Manually flag that your Claude quota is running low (ADR-314 power saver)',
|
|
111
|
+
options: [
|
|
112
|
+
{ name: 'clear', description: 'Clear the flag', type: 'boolean', default: false },
|
|
113
|
+
],
|
|
114
|
+
action: async (ctx) => {
|
|
115
|
+
if (ctx.flags.clear) {
|
|
116
|
+
const changed = clearQuotaLowStatus();
|
|
117
|
+
if (!changed) {
|
|
118
|
+
output.printError('Quota-low flag was just toggled — try again in a few minutes (ADR-314 anti-abuse cooldown).');
|
|
119
|
+
return { success: false };
|
|
120
|
+
}
|
|
121
|
+
output.printSuccess('Quota-low flag cleared.');
|
|
122
|
+
return { success: true };
|
|
123
|
+
}
|
|
124
|
+
const changed = markQuotaLow();
|
|
125
|
+
if (!changed) {
|
|
126
|
+
output.printError('Quota-low flag was just toggled — try again in a few minutes (ADR-314 anti-abuse cooldown).');
|
|
127
|
+
return { success: false };
|
|
128
|
+
}
|
|
129
|
+
output.printSuccess('Quota-low flag set.');
|
|
130
|
+
output.writeln('');
|
|
131
|
+
output.writeln('This is a manual, self-reported flag — ruflo cannot read your actual');
|
|
132
|
+
output.writeln('quota percentage today (see ADR-312/314). While flagged, and once you');
|
|
133
|
+
output.writeln('enable power saver mode, everyday requests route through Cognitum\'s');
|
|
134
|
+
output.writeln('own difficulty-based router (billed to your own Cognitum account):');
|
|
135
|
+
output.writeln(' ruflo proxy power-saver-enable');
|
|
136
|
+
output.writeln('');
|
|
137
|
+
output.writeln('Clear it any time: ruflo settings notices quota-low --clear');
|
|
138
|
+
const notice = quotaLowNotice();
|
|
139
|
+
return { success: true, data: { notice, status: readQuotaLowStatus() } };
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
const noticesCommand = {
|
|
143
|
+
name: 'notices',
|
|
144
|
+
description: 'Control the statusline notices row',
|
|
145
|
+
subcommands: [noticesStatusSub, noticesOffSub, noticesOnSub, noticesIdSub, rateLimitedSub, quotaLowSub],
|
|
146
|
+
action: noticesStatusSub.action,
|
|
147
|
+
};
|
|
148
|
+
const overviewAction = async () => {
|
|
149
|
+
const decision = resolveFunnelEnabled();
|
|
150
|
+
const disclosure = getDisclosure();
|
|
151
|
+
const consents = readConsents();
|
|
152
|
+
output.writeln('ruflo settings — user preferences');
|
|
153
|
+
output.writeln('');
|
|
154
|
+
output.writeln('Notices (statusline tips + product updates)');
|
|
155
|
+
output.writeln(' ruflo settings notices status Show current state');
|
|
156
|
+
output.writeln(' ruflo settings notices off Turn off all notices');
|
|
157
|
+
output.writeln(' ruflo settings notices on Re-enable');
|
|
158
|
+
output.writeln(' ruflo settings notices id Show pseudonymous notices id');
|
|
159
|
+
output.writeln('');
|
|
160
|
+
output.writeln(` current: ${decision.enabled ? 'enabled' : 'disabled'} (${decision.decidedBy})`);
|
|
161
|
+
output.writeln(` disclosure: ${disclosure.state}`);
|
|
162
|
+
const domains = Object.keys(consents);
|
|
163
|
+
if (domains.length) {
|
|
164
|
+
output.writeln(` consents: ${domains.join(', ')}`);
|
|
165
|
+
}
|
|
166
|
+
output.writeln(` state dir: ${funnelStateDir()}`);
|
|
167
|
+
return { success: true, data: { decision, disclosure: disclosure.state, consents } };
|
|
168
|
+
};
|
|
169
|
+
export const settingsCommand = {
|
|
170
|
+
name: 'settings',
|
|
171
|
+
description: 'View and change user preferences (notices, consents)',
|
|
172
|
+
subcommands: [noticesCommand],
|
|
173
|
+
examples: [
|
|
174
|
+
{ command: 'ruflo settings', description: 'Overview + current state' },
|
|
175
|
+
{ command: 'ruflo settings notices off', description: 'Turn off statusline notices' },
|
|
176
|
+
{ command: 'ruflo settings notices status', description: 'Show current notices state' },
|
|
177
|
+
],
|
|
178
|
+
action: overviewAction,
|
|
179
|
+
};
|
|
180
|
+
//# sourceMappingURL=settings.js.map
|