robrain 2.4.6 → 2.4.8
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 +3 -0
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +6 -8
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/explain.d.ts.map +1 -1
- package/dist/commands/explain.js +5 -8
- package/dist/commands/explain.js.map +1 -1
- package/dist/commands/export-interchange.d.ts.map +1 -1
- package/dist/commands/export-interchange.js +4 -9
- package/dist/commands/export-interchange.js.map +1 -1
- package/dist/commands/export-memory.d.ts.map +1 -1
- package/dist/commands/export-memory.js +4 -9
- package/dist/commands/export-memory.js.map +1 -1
- package/dist/commands/inject.d.ts.map +1 -1
- package/dist/commands/inject.js +5 -9
- package/dist/commands/inject.js.map +1 -1
- package/dist/commands/install.d.ts +7 -1
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +40 -3
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/install.test.js +89 -0
- package/dist/commands/install.test.js.map +1 -1
- package/dist/commands/outcomes.d.ts.map +1 -1
- package/dist/commands/outcomes.js +5 -13
- package/dist/commands/outcomes.js.map +1 -1
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +4 -5
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/status.d.ts +20 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +87 -29
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/status.test.d.ts +2 -0
- package/dist/commands/status.test.d.ts.map +1 -0
- package/dist/commands/status.test.js +201 -0
- package/dist/commands/status.test.js.map +1 -0
- package/dist/commands/synth.d.ts.map +1 -1
- package/dist/commands/synth.js +54 -15
- package/dist/commands/synth.js.map +1 -1
- package/dist/commands/synth.test.d.ts +2 -0
- package/dist/commands/synth.test.d.ts.map +1 -0
- package/dist/commands/synth.test.js +161 -0
- package/dist/commands/synth.test.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/lib/auth.d.ts +30 -2
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +45 -5
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/auth.test.d.ts +2 -0
- package/dist/lib/auth.test.d.ts.map +1 -0
- package/dist/lib/auth.test.js +46 -0
- package/dist/lib/auth.test.js.map +1 -0
- package/dist/lib/config.d.ts +7 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +12 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/load-env.d.ts +9 -0
- package/dist/lib/load-env.d.ts.map +1 -1
- package/dist/lib/load-env.js +13 -2
- package/dist/lib/load-env.js.map +1 -1
- package/dist/lib/perception-errors.d.ts +33 -0
- package/dist/lib/perception-errors.d.ts.map +1 -0
- package/dist/lib/perception-errors.js +104 -0
- package/dist/lib/perception-errors.js.map +1 -0
- package/dist/lib/perception-errors.test.d.ts +2 -0
- package/dist/lib/perception-errors.test.d.ts.map +1 -0
- package/dist/lib/perception-errors.test.js +64 -0
- package/dist/lib/perception-errors.test.js.map +1 -0
- package/dist/lib/project.d.ts +9 -0
- package/dist/lib/project.d.ts.map +1 -1
- package/dist/lib/project.js +17 -9
- package/dist/lib/project.js.map +1 -1
- package/package.json +2 -2
- package/vendor/sensing-mcp/dist/index.js +1 -1
- package/vendor/sensing-mcp/package.json +1 -1
- package/vendor/synthesis/dist/index.js +10 -1
- package/vendor/synthesis/package.json +1 -1
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { after, describe, it } from 'node:test';
|
|
5
|
+
import assert from 'node:assert/strict';
|
|
6
|
+
// config.ts resolves homedir() at import time — pin a hermetic HOME (and kill
|
|
7
|
+
// colour, so assertions match plain substrings) BEFORE the dynamic imports.
|
|
8
|
+
const fakeHome = mkdtempSync(join(tmpdir(), 'robrain-synth-'));
|
|
9
|
+
process.env.HOME = fakeHome;
|
|
10
|
+
process.env.FORCE_COLOR = '0';
|
|
11
|
+
mkdirSync(join(fakeHome, '.robrain'), { recursive: true });
|
|
12
|
+
// A directory that is deliberately NOT a robrain checkout. Entry resolution
|
|
13
|
+
// fails fast there, which is what makes this file hermetic: a run that reached
|
|
14
|
+
// resolution is distinguishable from one the cloud guard short-circuited —
|
|
15
|
+
// and neither ever spawns Synthesis or touches a database.
|
|
16
|
+
const notACheckout = join(fakeHome, 'not-a-checkout');
|
|
17
|
+
mkdirSync(notACheckout, { recursive: true });
|
|
18
|
+
process.env.ROBRAIN_REPO = notACheckout;
|
|
19
|
+
// Ambient DATABASE_URL would flip the mode routing below — own it per test.
|
|
20
|
+
delete process.env.DATABASE_URL;
|
|
21
|
+
const { isCloudInstall } = await import('../lib/config.js');
|
|
22
|
+
const { synthCommand } = await import('./synth.js');
|
|
23
|
+
function writeInstallConfig(config) {
|
|
24
|
+
writeFileSync(join(fakeHome, '.robrain', 'config.json'), JSON.stringify(config));
|
|
25
|
+
}
|
|
26
|
+
/** Run `robrain synth` with console captured and a clean exit code. */
|
|
27
|
+
async function runSynth() {
|
|
28
|
+
const lines = [];
|
|
29
|
+
const { log, error } = console;
|
|
30
|
+
console.log = (...args) => { lines.push(args.join(' ')); };
|
|
31
|
+
console.error = (...args) => { lines.push(args.join(' ')); };
|
|
32
|
+
process.exitCode = 0;
|
|
33
|
+
try {
|
|
34
|
+
await synthCommand({});
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
console.log = log;
|
|
38
|
+
console.error = error;
|
|
39
|
+
}
|
|
40
|
+
const exitCode = Number(process.exitCode ?? 0);
|
|
41
|
+
process.exitCode = 0;
|
|
42
|
+
return { out: lines.join('\n'), exitCode };
|
|
43
|
+
}
|
|
44
|
+
const CLOUD_MESSAGE = 'Synthesis runs server-side on Rory Plans cloud';
|
|
45
|
+
const RESOLVE_FAILURE = 'does not look like a robrain checkout';
|
|
46
|
+
after(() => {
|
|
47
|
+
rmSync(fakeHome, { recursive: true, force: true });
|
|
48
|
+
});
|
|
49
|
+
describe('isCloudInstall', () => {
|
|
50
|
+
it('is true for a cloud thin-client install', () => {
|
|
51
|
+
writeInstallConfig({ token: 'rory_x', email: 'dev@example.com', thin: true });
|
|
52
|
+
assert.equal(isCloudInstall(), true);
|
|
53
|
+
});
|
|
54
|
+
it('is false for a self-hosted install', () => {
|
|
55
|
+
writeInstallConfig({ selfHosted: true, perceptionUrl: 'http://127.0.0.1:3001' });
|
|
56
|
+
assert.equal(isCloudInstall(), false);
|
|
57
|
+
});
|
|
58
|
+
it('is false when a cloud login also runs a local stack (selfHosted wins)', () => {
|
|
59
|
+
// `robrain up` merges selfHosted onto an existing cloud config — that user
|
|
60
|
+
// does have a local Postgres, so synth must stay available to them.
|
|
61
|
+
writeInstallConfig({ token: 'rory_x', thin: true, selfHosted: true });
|
|
62
|
+
assert.equal(isCloudInstall(), false);
|
|
63
|
+
});
|
|
64
|
+
it('is true for a legacy cloud install that predates the thin flag', () => {
|
|
65
|
+
// Cloud installs before `thin` existed carry only token/email. Nothing
|
|
66
|
+
// self-hosted writes a Rory token, so token-without-thin means cloud.
|
|
67
|
+
writeInstallConfig({ token: 'rory_x', email: 'dev@example.com', perceptionUrl: 'https://api.roryplans.ai' });
|
|
68
|
+
assert.equal(isCloudInstall(), true);
|
|
69
|
+
});
|
|
70
|
+
it('is false for a legacy self-hosted install with no flags', () => {
|
|
71
|
+
// Pre-`selfHosted` installs: Perception configured, never logged into Rory.
|
|
72
|
+
writeInstallConfig({ perceptionUrl: 'http://127.0.0.1:3001', installedAt: '2026-01-01T00:00:00Z' });
|
|
73
|
+
assert.equal(isCloudInstall(), false);
|
|
74
|
+
});
|
|
75
|
+
it('is false with no config at all', () => {
|
|
76
|
+
writeInstallConfig({});
|
|
77
|
+
assert.equal(isCloudInstall(), false);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe('robrain synth — install mode routing', () => {
|
|
81
|
+
it('explains itself and exits 0 on a cloud install', async () => {
|
|
82
|
+
writeInstallConfig({ token: 'rory_x', email: 'dev@example.com', thin: true });
|
|
83
|
+
const { out, exitCode } = await runSynth();
|
|
84
|
+
assert.match(out, new RegExp(CLOUD_MESSAGE));
|
|
85
|
+
assert.match(out, /npx robrain review/); // says where results DO surface
|
|
86
|
+
assert.match(out, /npx robrain up/); // …and how to opt into a local pass
|
|
87
|
+
assert.equal(exitCode, 0, 'a cloud install is not an error state');
|
|
88
|
+
// The guard must short-circuit BEFORE entry resolution — otherwise a cloud
|
|
89
|
+
// user still eats a resolution/DATABASE_URL failure.
|
|
90
|
+
assert.doesNotMatch(out, new RegExp(RESOLVE_FAILURE));
|
|
91
|
+
});
|
|
92
|
+
it('runs the normal path on a self-hosted install', async () => {
|
|
93
|
+
writeInstallConfig({ selfHosted: true, perceptionUrl: 'http://127.0.0.1:3001' });
|
|
94
|
+
const { out, exitCode } = await runSynth();
|
|
95
|
+
// Same environment as the cloud case — only the install mode differs, and
|
|
96
|
+
// here we reach entry resolution (which this fake HOME makes fail cleanly).
|
|
97
|
+
assert.match(out, new RegExp(RESOLVE_FAILURE));
|
|
98
|
+
assert.doesNotMatch(out, new RegExp(CLOUD_MESSAGE));
|
|
99
|
+
assert.equal(exitCode, 1, 'a real synth failure must stay non-zero for scripts');
|
|
100
|
+
});
|
|
101
|
+
it('still runs when a stale cloud token sits on top of a real DATABASE_URL', async () => {
|
|
102
|
+
// Logged into Rory once, never logged out, now self-hosting by hand (no
|
|
103
|
+
// `robrain up`, so no selfHosted flag). Refusing here would tell someone
|
|
104
|
+
// with a working local store that there is nothing to run — silently, and
|
|
105
|
+
// with exit 0. A store you can point at wins over a leftover token.
|
|
106
|
+
writeInstallConfig({ token: 'rory_stale', email: 'dev@example.com', thin: true });
|
|
107
|
+
process.env.DATABASE_URL = 'postgres://robrain:pw@127.0.0.1:5432/robrain';
|
|
108
|
+
try {
|
|
109
|
+
const { out, exitCode } = await runSynth();
|
|
110
|
+
assert.doesNotMatch(out, new RegExp(CLOUD_MESSAGE));
|
|
111
|
+
assert.match(out, new RegExp(RESOLVE_FAILURE)); // reached resolution = would have run
|
|
112
|
+
assert.equal(exitCode, 1);
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
delete process.env.DATABASE_URL;
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
it('counts a resolved checkout\'s .env as a local store, like the child would', async () => {
|
|
119
|
+
// The narrow case the config-only guard still got wrong: cloud token, no
|
|
120
|
+
// `robrain up`, DATABASE_URL living ONLY in a checkout's .env — a file the
|
|
121
|
+
// parent never reads but the child's own loadEnv does. Declining here
|
|
122
|
+
// refuses work that would have succeeded.
|
|
123
|
+
const checkout = join(fakeHome, 'checkout');
|
|
124
|
+
const distDir = join(checkout, 'packages', 'synthesis', 'dist');
|
|
125
|
+
mkdirSync(distDir, { recursive: true });
|
|
126
|
+
// Stand-in for the Synthesis bundle: records the DATABASE_URL it was
|
|
127
|
+
// handed, so this asserts what the child actually got — not just that the
|
|
128
|
+
// parent decided to spawn. CJS on purpose (no package.json type here).
|
|
129
|
+
const marker = join(fakeHome, 'child-saw.txt');
|
|
130
|
+
writeFileSync(join(distDir, 'index.js'), `require('fs').writeFileSync(${JSON.stringify(marker)}, String(process.env.DATABASE_URL))\n`);
|
|
131
|
+
const repoDbUrl = 'postgres://robrain:pw@127.0.0.1:5432/from_checkout_env';
|
|
132
|
+
writeFileSync(join(checkout, '.env'), `DATABASE_URL=${repoDbUrl}\n`);
|
|
133
|
+
writeInstallConfig({ token: 'rory_stale', email: 'dev@example.com', thin: true });
|
|
134
|
+
process.env.ROBRAIN_REPO = checkout;
|
|
135
|
+
try {
|
|
136
|
+
const { out, exitCode } = await runSynth();
|
|
137
|
+
assert.doesNotMatch(out, new RegExp(CLOUD_MESSAGE), 'a store in the checkout .env must win over the token');
|
|
138
|
+
assert.equal(exitCode, 0);
|
|
139
|
+
assert.equal(readFileSync(marker, 'utf8'), repoDbUrl, 'child must receive the checkout .env DATABASE_URL');
|
|
140
|
+
}
|
|
141
|
+
finally {
|
|
142
|
+
process.env.ROBRAIN_REPO = notACheckout;
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
it('prefers the cloud explanation over a resolution failure', async () => {
|
|
146
|
+
// A cloud install has no local Synthesis to find — "we could not locate the
|
|
147
|
+
// bundle" is a true but useless answer; the mode is the actual reason.
|
|
148
|
+
writeInstallConfig({ token: 'rory_x', email: 'dev@example.com', thin: true });
|
|
149
|
+
const { out, exitCode } = await runSynth();
|
|
150
|
+
assert.match(out, new RegExp(CLOUD_MESSAGE));
|
|
151
|
+
assert.doesNotMatch(out, new RegExp(RESOLVE_FAILURE));
|
|
152
|
+
assert.equal(exitCode, 0);
|
|
153
|
+
});
|
|
154
|
+
it('names the stale-token escape hatch when it does decline', async () => {
|
|
155
|
+
writeInstallConfig({ token: 'rory_stale', email: 'dev@example.com', thin: true });
|
|
156
|
+
const { out } = await runSynth();
|
|
157
|
+
assert.match(out, /npx robrain logout/);
|
|
158
|
+
assert.match(out, /DATABASE_URL/);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
//# sourceMappingURL=synth.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"synth.test.js","sourceRoot":"","sources":["../../src/commands/synth.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -30,7 +30,7 @@ import { projectsListCommand, projectsMergeCommand } from './commands/projects.j
|
|
|
30
30
|
import { upCommand, downCommand, DEFAULT_IMAGE_REPO } from './commands/up.js';
|
|
31
31
|
import { mcpCommand } from './commands/mcp.js';
|
|
32
32
|
import { installHermesPlugin, resolveHermesHome } from './lib/hermes-plugin.js';
|
|
33
|
-
const VERSION = '2.4.
|
|
33
|
+
const VERSION = '2.4.8';
|
|
34
34
|
program
|
|
35
35
|
.name('robrain')
|
|
36
36
|
.description('Institutional memory for AI coding agents — by Rory Plans')
|
package/dist/lib/auth.d.ts
CHANGED
|
@@ -4,6 +4,30 @@ export interface AuthResult {
|
|
|
4
4
|
perceptionUrl?: string;
|
|
5
5
|
planningUrl?: string;
|
|
6
6
|
error?: string;
|
|
7
|
+
/** Account is fine, the plan is not — see PlanRequirement. */
|
|
8
|
+
planRequired?: PlanRequirement;
|
|
9
|
+
}
|
|
10
|
+
/** "Your login worked; your plan doesn't include RoBrain cloud." */
|
|
11
|
+
export interface PlanRequirement {
|
|
12
|
+
/** Plan the account is on today, when the API reports it (e.g. "free"). */
|
|
13
|
+
currentPlan?: string;
|
|
14
|
+
/** Minimum plan that includes RoBrain cloud. */
|
|
15
|
+
requiredPlan: string;
|
|
16
|
+
/** Only false when the API says the trial is used up or unavailable. */
|
|
17
|
+
trialAvailable: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Recognize an entitlement refusal across the shapes the API might use, so the
|
|
21
|
+
* CLI can say "upgrade" instead of "authentication failed" / "contact support":
|
|
22
|
+
* • 402 Payment Required (preferred), or
|
|
23
|
+
* • 401/403 carrying a plan error code, or a message naming plan/subscription/upgrade/trial.
|
|
24
|
+
* Deliberately narrow on 401/403 — a plain bad token must stay an auth error.
|
|
25
|
+
*/
|
|
26
|
+
export declare function detectPlanRequirement(status: number, body: unknown): PlanRequirement | null;
|
|
27
|
+
/** Outcome of provisioning: config, an entitlement refusal, or an opaque failure. */
|
|
28
|
+
export interface ProvisionResult {
|
|
29
|
+
config?: ProvisionedConfig;
|
|
30
|
+
planRequired?: PlanRequirement;
|
|
7
31
|
}
|
|
8
32
|
export interface ProvisionedConfig {
|
|
9
33
|
perceptionUrl: string;
|
|
@@ -14,8 +38,12 @@ export interface ProvisionedConfig {
|
|
|
14
38
|
}
|
|
15
39
|
/** Validate a Rory Plans token and return account info */
|
|
16
40
|
export declare function validateToken(token: string): Promise<AuthResult>;
|
|
17
|
-
/**
|
|
18
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Fetch provisioned API config for this token. An account on a plan without
|
|
43
|
+
* RoBrain cloud lands here (the token is valid — there is just nothing to
|
|
44
|
+
* provision), so entitlement is reported rather than folded into a failure.
|
|
45
|
+
*/
|
|
46
|
+
export declare function fetchProvisionedConfig(token: string): Promise<ProvisionResult>;
|
|
19
47
|
/** Register a new project with Rory Plans */
|
|
20
48
|
export declare function registerProject(token: string, projectId: string, projectName: string): Promise<boolean>;
|
|
21
49
|
//# sourceMappingURL=auth.d.ts.map
|
package/dist/lib/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAa,OAAO,CAAA;IACtB,KAAK,CAAC,EAAS,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,WAAW,CAAC,EAAG,MAAM,CAAA;IACrB,KAAK,CAAC,EAAS,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAa,OAAO,CAAA;IACtB,KAAK,CAAC,EAAS,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,WAAW,CAAC,EAAG,MAAM,CAAA;IACrB,KAAK,CAAC,EAAS,MAAM,CAAA;IACrB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,eAAe,CAAA;CAC/B;AAED,oEAAoE;AACpE,MAAM,WAAW,eAAe;IAC9B,2EAA2E;IAC3E,WAAW,CAAC,EAAI,MAAM,CAAA;IACtB,gDAAgD;IAChD,YAAY,EAAI,MAAM,CAAA;IACtB,wEAAwE;IACxE,cAAc,EAAE,OAAO,CAAA;CACxB;AAMD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,eAAe,GAAG,IAAI,CAoB3F;AAED,qFAAqF;AACrF,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAQ,iBAAiB,CAAA;IAChC,YAAY,CAAC,EAAE,eAAe,CAAA;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAI,MAAM,CAAA;IACrB,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAI,MAAM,CAAA;IACrB,iBAAiB,EAAE,MAAM,CAAA;CAC1B;AAED,0DAA0D;AAC1D,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAsCtE;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAkBpF;AAED,6CAA6C;AAC7C,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,OAAO,CAAC,CAclB"}
|
package/dist/lib/auth.js
CHANGED
|
@@ -5,6 +5,36 @@
|
|
|
5
5
|
// Perception/Planning API URLs for this account.
|
|
6
6
|
// ─────────────────────────────────────────────────────────────
|
|
7
7
|
import { RORY_API_BASE } from './config.js';
|
|
8
|
+
const PLAN_ERROR_CODES = new Set([
|
|
9
|
+
'plan_required', 'upgrade_required', 'subscription_required', 'payment_required',
|
|
10
|
+
]);
|
|
11
|
+
/**
|
|
12
|
+
* Recognize an entitlement refusal across the shapes the API might use, so the
|
|
13
|
+
* CLI can say "upgrade" instead of "authentication failed" / "contact support":
|
|
14
|
+
* • 402 Payment Required (preferred), or
|
|
15
|
+
* • 401/403 carrying a plan error code, or a message naming plan/subscription/upgrade/trial.
|
|
16
|
+
* Deliberately narrow on 401/403 — a plain bad token must stay an auth error.
|
|
17
|
+
*/
|
|
18
|
+
export function detectPlanRequirement(status, body) {
|
|
19
|
+
const b = (body ?? {});
|
|
20
|
+
const code = String(b.code ?? b.error ?? '').toLowerCase();
|
|
21
|
+
const text = String(b.message ?? b.error ?? '').toLowerCase();
|
|
22
|
+
const hasPlanCode = PLAN_ERROR_CODES.has(code);
|
|
23
|
+
const hasPlanText = /\b(plan|subscription|upgrade|trial|billing)\b/.test(text);
|
|
24
|
+
const hasPlanFields = typeof b.required_plan === 'string' ||
|
|
25
|
+
typeof b.plan === 'string' ||
|
|
26
|
+
typeof b.trial_available === 'boolean';
|
|
27
|
+
const looksLikePlan = hasPlanCode ||
|
|
28
|
+
((status === 401 || status === 403 || status === 402) && hasPlanText) ||
|
|
29
|
+
(status === 402 && hasPlanFields);
|
|
30
|
+
if (!looksLikePlan)
|
|
31
|
+
return null;
|
|
32
|
+
return {
|
|
33
|
+
currentPlan: typeof b.plan === 'string' ? b.plan : undefined,
|
|
34
|
+
requiredPlan: typeof b.required_plan === 'string' ? b.required_plan : 'Pro',
|
|
35
|
+
trialAvailable: b.trial_available !== false,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
8
38
|
/** Validate a Rory Plans token and return account info */
|
|
9
39
|
export async function validateToken(token) {
|
|
10
40
|
try {
|
|
@@ -17,6 +47,9 @@ export async function validateToken(token) {
|
|
|
17
47
|
});
|
|
18
48
|
if (!res.ok) {
|
|
19
49
|
const body = await res.json().catch(() => ({}));
|
|
50
|
+
const planRequired = detectPlanRequirement(res.status, body);
|
|
51
|
+
if (planRequired)
|
|
52
|
+
return { ok: false, planRequired };
|
|
20
53
|
return {
|
|
21
54
|
ok: false,
|
|
22
55
|
error: body.error ?? `Authentication failed (${res.status})`,
|
|
@@ -37,20 +70,27 @@ export async function validateToken(token) {
|
|
|
37
70
|
};
|
|
38
71
|
}
|
|
39
72
|
}
|
|
40
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* Fetch provisioned API config for this token. An account on a plan without
|
|
75
|
+
* RoBrain cloud lands here (the token is valid — there is just nothing to
|
|
76
|
+
* provision), so entitlement is reported rather than folded into a failure.
|
|
77
|
+
*/
|
|
41
78
|
export async function fetchProvisionedConfig(token) {
|
|
42
79
|
try {
|
|
43
80
|
const res = await fetch(`${RORY_API_BASE}/robrain/provision`, {
|
|
44
81
|
method: 'GET',
|
|
45
82
|
headers: { 'Authorization': `Bearer ${token}` },
|
|
46
83
|
});
|
|
47
|
-
if (!res.ok)
|
|
48
|
-
|
|
84
|
+
if (!res.ok) {
|
|
85
|
+
const body = await res.json().catch(() => ({}));
|
|
86
|
+
const planRequired = detectPlanRequirement(res.status, body);
|
|
87
|
+
return planRequired ? { planRequired } : {};
|
|
88
|
+
}
|
|
49
89
|
const data = await res.json();
|
|
50
|
-
return data;
|
|
90
|
+
return { config: data };
|
|
51
91
|
}
|
|
52
92
|
catch {
|
|
53
|
-
return
|
|
93
|
+
return {};
|
|
54
94
|
}
|
|
55
95
|
}
|
|
56
96
|
/** Register a new project with Rory Plans */
|
package/dist/lib/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAAA,kBAAkB;AAClB,gEAAgE;AAChE,iDAAiD;AACjD,6DAA6D;AAC7D,iDAAiD;AACjD,gEAAgE;AAEhE,OAAO,EAAE,aAAa,EAAuB,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.test.d.ts","sourceRoot":"","sources":["../../src/lib/auth.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { detectPlanRequirement } from './auth.js';
|
|
4
|
+
describe('detectPlanRequirement — entitlement vs. everything else', () => {
|
|
5
|
+
it('reads 402 Payment Required as a plan problem', () => {
|
|
6
|
+
const req = detectPlanRequirement(402, { error: 'plan_required', plan: 'free', required_plan: 'Pro' });
|
|
7
|
+
assert.deepEqual(req, { currentPlan: 'free', requiredPlan: 'Pro', trialAvailable: true });
|
|
8
|
+
});
|
|
9
|
+
it('does not misclassify ambiguous 402 errors as plan-required', () => {
|
|
10
|
+
assert.equal(detectPlanRequirement(402, { error: 'Payment Required' }), null);
|
|
11
|
+
assert.equal(detectPlanRequirement(402, {}), null);
|
|
12
|
+
});
|
|
13
|
+
it('reads a 403 carrying a plan error code', () => {
|
|
14
|
+
const req = detectPlanRequirement(403, { code: 'upgrade_required' });
|
|
15
|
+
assert.ok(req);
|
|
16
|
+
assert.equal(req.requiredPlan, 'Pro'); // default when the API does not name one
|
|
17
|
+
});
|
|
18
|
+
it('reads a 403 whose message names the plan, without a code', () => {
|
|
19
|
+
const req = detectPlanRequirement(403, { error: 'Your subscription does not include RoBrain' });
|
|
20
|
+
assert.ok(req);
|
|
21
|
+
});
|
|
22
|
+
it('leaves a plain bad token as an auth error', () => {
|
|
23
|
+
// The failure mode to avoid in both directions: a mistyped token must not
|
|
24
|
+
// be answered with "upgrade your plan".
|
|
25
|
+
assert.equal(detectPlanRequirement(401, { error: 'Invalid token' }), null);
|
|
26
|
+
assert.equal(detectPlanRequirement(401, {}), null);
|
|
27
|
+
assert.equal(detectPlanRequirement(403, { error: 'Forbidden' }), null);
|
|
28
|
+
});
|
|
29
|
+
it('leaves server and network failures alone', () => {
|
|
30
|
+
assert.equal(detectPlanRequirement(500, { error: 'Internal error' }), null);
|
|
31
|
+
assert.equal(detectPlanRequirement(404, {}), null);
|
|
32
|
+
assert.equal(detectPlanRequirement(502, undefined), null);
|
|
33
|
+
});
|
|
34
|
+
it('honours an exhausted trial, and assumes one is available otherwise', () => {
|
|
35
|
+
// Offering "start your free trial" to someone who already used theirs is
|
|
36
|
+
// the one line here that can be actively wrong.
|
|
37
|
+
assert.equal(detectPlanRequirement(402, { error: 'plan_required', trial_available: false })?.trialAvailable, false);
|
|
38
|
+
assert.equal(detectPlanRequirement(402, { error: 'plan_required' })?.trialAvailable, true);
|
|
39
|
+
});
|
|
40
|
+
it('passes through the plan names the API reports', () => {
|
|
41
|
+
const req = detectPlanRequirement(402, { error: 'plan_required', plan: 'free', required_plan: 'Teams' });
|
|
42
|
+
assert.equal(req?.currentPlan, 'free');
|
|
43
|
+
assert.equal(req?.requiredPlan, 'Teams');
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=auth.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.test.js","sourceRoot":"","sources":["../../src/lib/auth.test.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -25,6 +25,13 @@ export declare function writeConfig(config: RoMemoryConfig): void;
|
|
|
25
25
|
export declare function mergeConfig(updates: Partial<RoMemoryConfig>): void;
|
|
26
26
|
/** True if Rory cloud login, or OSS self-hosted install (no Rory token). */
|
|
27
27
|
export declare function isAuthenticated(): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* True when this install talks to the managed Rory Plans API rather than a
|
|
30
|
+
* local stack — i.e. there is no local Postgres for batch jobs to open.
|
|
31
|
+
* `selfHosted` wins: `robrain up` merges that flag in, so a user who has both
|
|
32
|
+
* a cloud login and a local stack still counts as self-hosted.
|
|
33
|
+
*/
|
|
34
|
+
export declare function isCloudInstall(): boolean;
|
|
28
35
|
export declare function getToken(): string | undefined;
|
|
29
36
|
export declare const RORY_API_BASE: string;
|
|
30
37
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/lib/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAW,MAAM,CAAA;IACvB,KAAK,CAAC,EAAW,MAAM,CAAA;IACvB,2DAA2D;IAC3D,UAAU,CAAC,EAAM,OAAO,CAAA;IACxB,2FAA2F;IAC3F,IAAI,CAAC,EAAY,OAAO,CAAA;IACxB,aAAa,CAAC,EAAG,MAAM,CAAA;IACvB,aAAa,CAAC,EAAG,MAAM,CAAA;IACvB,WAAW,CAAC,EAAK,MAAM,CAAA;IACvB,WAAW,CAAC,EAAK,MAAM,CAAA;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,YAAY,CAAC,EAAI,MAAM,CAAA;IACvB,WAAW,CAAC,EAAK,MAAM,CAAA;IACvB,OAAO,CAAC,EAAS,MAAM,CAAA;CACxB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAWxD;AAED,wBAAgB,UAAU,IAAI,cAAc,CAS3C;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAKxD;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI,CAGlE;AAED,4EAA4E;AAC5E,wBAAgB,eAAe,IAAI,OAAO,CAWzC;AAED,wBAAgB,QAAQ,IAAI,MAAM,GAAG,SAAS,CAE7C;AAGD,eAAO,MAAM,aAAa,QAA0D,CAAA"}
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAW,MAAM,CAAA;IACvB,KAAK,CAAC,EAAW,MAAM,CAAA;IACvB,2DAA2D;IAC3D,UAAU,CAAC,EAAM,OAAO,CAAA;IACxB,2FAA2F;IAC3F,IAAI,CAAC,EAAY,OAAO,CAAA;IACxB,aAAa,CAAC,EAAG,MAAM,CAAA;IACvB,aAAa,CAAC,EAAG,MAAM,CAAA;IACvB,WAAW,CAAC,EAAK,MAAM,CAAA;IACvB,WAAW,CAAC,EAAK,MAAM,CAAA;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,YAAY,CAAC,EAAI,MAAM,CAAA;IACvB,WAAW,CAAC,EAAK,MAAM,CAAA;IACvB,OAAO,CAAC,EAAS,MAAM,CAAA;CACxB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAWxD;AAED,wBAAgB,UAAU,IAAI,cAAc,CAS3C;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAKxD;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI,CAGlE;AAED,4EAA4E;AAC5E,wBAAgB,eAAe,IAAI,OAAO,CAWzC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAIxC;AAED,wBAAgB,QAAQ,IAAI,MAAM,GAAG,SAAS,CAE7C;AAGD,eAAO,MAAM,aAAa,QAA0D,CAAA"}
|
package/dist/lib/config.js
CHANGED
|
@@ -62,6 +62,18 @@ export function isAuthenticated() {
|
|
|
62
62
|
!config.token &&
|
|
63
63
|
!config.email);
|
|
64
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* True when this install talks to the managed Rory Plans API rather than a
|
|
67
|
+
* local stack — i.e. there is no local Postgres for batch jobs to open.
|
|
68
|
+
* `selfHosted` wins: `robrain up` merges that flag in, so a user who has both
|
|
69
|
+
* a cloud login and a local stack still counts as self-hosted.
|
|
70
|
+
*/
|
|
71
|
+
export function isCloudInstall() {
|
|
72
|
+
const config = readConfig();
|
|
73
|
+
if (config.selfHosted)
|
|
74
|
+
return false;
|
|
75
|
+
return Boolean(config.thin || config.token);
|
|
76
|
+
}
|
|
65
77
|
export function getToken() {
|
|
66
78
|
return readConfig().token;
|
|
67
79
|
}
|
package/dist/lib/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,oBAAoB;AACpB,gEAAgE;AAChE,gEAAgE;AAChE,sEAAsE;AACtE,gEAAgE;AAEhE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,IAAI,CAAA;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAA;AAC5B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,MAAM,UAAU,GAAI,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAA;AAC/C,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAA;AAmBnD;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;QACtB,IAAI,CAAC,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;YAC/B,CAAC,CAAC,QAAQ,GAAG,WAAW,CAAA;YACxB,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;QACxC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,oCAAoC;IACtC,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,EAAE,CAAA;IACvC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAmB,CAAA;QAC9E,IAAI,MAAM,CAAC,aAAa;YAAE,MAAM,CAAC,aAAa,GAAG,oBAAoB,CAAC,MAAM,CAAC,aAAa,CAAC,CAAA;QAC3F,OAAO,MAAM,CAAA;IACf,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAsB;IAChD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC5C,CAAC;IACD,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;AACrE,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAgC;IAC1D,MAAM,OAAO,GAAG,UAAU,EAAE,CAAA;IAC5B,WAAW,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC,CAAA;AACzC,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,eAAe;IAC7B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;IAC3B,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IAC7C,IAAI,MAAM,CAAC,UAAU;QAAE,OAAO,IAAI,CAAA;IAClC,2FAA2F;IAC3F,OAAO,OAAO,CACZ,MAAM,CAAC,aAAa;QAClB,MAAM,CAAC,WAAW;QAClB,CAAC,MAAM,CAAC,KAAK;QACb,CAAC,MAAM,CAAC,KAAK,CAChB,CAAA;AACH,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,OAAO,UAAU,EAAE,CAAC,KAAK,CAAA;AAC3B,CAAC;AAED,iFAAiF;AACjF,MAAM,CAAC,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,0BAA0B,CAAA"}
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/load-env.d.ts
CHANGED
|
@@ -8,6 +8,15 @@ export declare function loadCliEnv(repoRoot?: string): void;
|
|
|
8
8
|
* runs first and this only fills the gaps.
|
|
9
9
|
*/
|
|
10
10
|
export declare function applyStackEnvFallback(env: NodeJS.ProcessEnv, stackEnvPath?: string): void;
|
|
11
|
+
/**
|
|
12
|
+
* Fill vars still unset/empty in `env` from an arbitrary `.env` file; no-op
|
|
13
|
+
* when it does not exist. Gaps only — never overrides what `env` already has.
|
|
14
|
+
*
|
|
15
|
+
* Lets a parent process see the same values a child that runs its own
|
|
16
|
+
* `loadEnv(<root>)` would (e.g. `robrain synth` deciding whether a store
|
|
17
|
+
* exists before spawning Synthesis against a checkout it resolved).
|
|
18
|
+
*/
|
|
19
|
+
export declare function applyEnvFileFallback(env: NodeJS.ProcessEnv, envPath: string): void;
|
|
11
20
|
/**
|
|
12
21
|
* When running the CLI from a git checkout (e.g. `node packages/cli/bin/robrain.js`),
|
|
13
22
|
* find that checkout's root so repo `.env` matches `pnpm docker:up` / docker-compose.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load-env.d.ts","sourceRoot":"","sources":["../../src/lib/load-env.ts"],"names":[],"mappings":"AAiDA,uFAAuF;AACvF,wBAAgB,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAIlD;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,YAAY,SAA+C,GAC1D,IAAI,
|
|
1
|
+
{"version":3,"file":"load-env.d.ts","sourceRoot":"","sources":["../../src/lib/load-env.ts"],"names":[],"mappings":"AAiDA,uFAAuF;AACvF,wBAAgB,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAIlD;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,YAAY,SAA+C,GAC1D,IAAI,CAEN;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAOlF;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,IAAI,MAAM,GAAG,SAAS,CAclE;AAED,6FAA6F;AAC7F,wBAAgB,+BAA+B,IAAI,MAAM,GAAG,SAAS,CASpE;AAED,yFAAyF;AACzF,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAO/E"}
|
package/dist/lib/load-env.js
CHANGED
|
@@ -50,9 +50,20 @@ export function loadCliEnv(repoRoot) {
|
|
|
50
50
|
* runs first and this only fills the gaps.
|
|
51
51
|
*/
|
|
52
52
|
export function applyStackEnvFallback(env, stackEnvPath = join(homedir(), '.robrain', 'stack', '.env')) {
|
|
53
|
-
|
|
53
|
+
applyEnvFileFallback(env, stackEnvPath);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Fill vars still unset/empty in `env` from an arbitrary `.env` file; no-op
|
|
57
|
+
* when it does not exist. Gaps only — never overrides what `env` already has.
|
|
58
|
+
*
|
|
59
|
+
* Lets a parent process see the same values a child that runs its own
|
|
60
|
+
* `loadEnv(<root>)` would (e.g. `robrain synth` deciding whether a store
|
|
61
|
+
* exists before spawning Synthesis against a checkout it resolved).
|
|
62
|
+
*/
|
|
63
|
+
export function applyEnvFileFallback(env, envPath) {
|
|
64
|
+
if (!existsSync(envPath))
|
|
54
65
|
return;
|
|
55
|
-
const parsed = dotenvParse().parse(readFileSync(
|
|
66
|
+
const parsed = dotenvParse().parse(readFileSync(envPath));
|
|
56
67
|
for (const [key, value] of Object.entries(parsed)) {
|
|
57
68
|
if (!isUnsetOrEmptyShell(env[key]) || value === '')
|
|
58
69
|
continue;
|
package/dist/lib/load-env.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load-env.js","sourceRoot":"","sources":["../../src/lib/load-env.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,8GAA8G;AAE9G,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AASxC,IAAI,YAAsC,CAAA;AAC1C,SAAS,WAAW;IAClB,YAAY,KAAK,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAiB,CAAA;IACzE,OAAO,YAAY,CAAA;AACrB,CAAC;AAED,uFAAuF;AACvF,SAAS,iBAAiB,CAAC,QAAiB;IAC1C,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAA;IACpC,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAA;IAC1C,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IACpB,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,SAAS,mBAAmB,CAAC,CAAqB;IAChD,OAAO,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,EAAE,CAAA;AACpC,CAAC;AAED,mGAAmG;AACnG,SAAS,gBAAgB,CAAC,IAAY;IACpC,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,CAAA;IAC9B,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACvC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAAE,SAAQ;QACpD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;IAC1B,CAAC;AACH,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,UAAU,CAAC,QAAiB;IAC1C,KAAK,MAAM,IAAI,IAAI,iBAAiB,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/C,IAAI,UAAU,CAAC,IAAI,CAAC;YAAE,gBAAgB,CAAC,IAAI,CAAC,CAAA;IAC9C,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CACnC,GAAsB,EACtB,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC;IAE3D,IAAI,CAAC,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"load-env.js","sourceRoot":"","sources":["../../src/lib/load-env.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface FailureExplanation {
|
|
2
|
+
headline: string;
|
|
3
|
+
hints: string[];
|
|
4
|
+
}
|
|
5
|
+
export interface FailureContext {
|
|
6
|
+
/** Cloud install (managed store) vs self-hosted (local Perception). */
|
|
7
|
+
cloud: boolean;
|
|
8
|
+
perceptionUrl: string;
|
|
9
|
+
}
|
|
10
|
+
/** Spinner-like sink so callers can pass ora, or a console shim. */
|
|
11
|
+
export interface FailSink {
|
|
12
|
+
fail(text: string): unknown;
|
|
13
|
+
}
|
|
14
|
+
/** Auth-failure hints, or [] when the status is not an auth failure. */
|
|
15
|
+
export declare function perceptionAuthHints(status: number, ctx: FailureContext): string[];
|
|
16
|
+
/**
|
|
17
|
+
* @param action what the caller was doing, for the unclassified fallback
|
|
18
|
+
* (e.g. "fetch decisions", "scan for prior rejections").
|
|
19
|
+
*/
|
|
20
|
+
export declare function explainPerceptionFailure(status: number, ctx: FailureContext, action?: string): FailureExplanation;
|
|
21
|
+
/** The store was never reached — DNS, refused connection, timeout. */
|
|
22
|
+
export declare function explainPerceptionUnreachable(ctx: FailureContext): FailureExplanation;
|
|
23
|
+
/**
|
|
24
|
+
* Print a status failure and exit.
|
|
25
|
+
* @param exitCode callers with their own contract override it — `robrain check`
|
|
26
|
+
* reserves 1 for "a rejection matched" and uses 2 for "could not scan".
|
|
27
|
+
*/
|
|
28
|
+
export declare function failPerception(sink: FailSink, status: number, ctx: FailureContext, action?: string, exitCode?: number): never;
|
|
29
|
+
/** Print an unreachable-store failure and exit. */
|
|
30
|
+
export declare function failPerceptionUnreachable(sink: FailSink, ctx: FailureContext, exitCode?: number): never;
|
|
31
|
+
/** Console-based sink for commands that do not use a spinner. */
|
|
32
|
+
export declare function consoleFailSink(): FailSink;
|
|
33
|
+
//# sourceMappingURL=perception-errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"perception-errors.d.ts","sourceRoot":"","sources":["../../src/lib/perception-errors.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAK,MAAM,EAAE,CAAA;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,KAAK,EAAU,OAAO,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;CACtB;AAED,oEAAoE;AACpE,MAAM,WAAW,QAAQ;IACvB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;CAC5B;AASD,wEAAwE;AACxE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,cAAc,GAAG,MAAM,EAAE,CAYjF;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,cAAc,EACnB,MAAM,SAAoB,GACzB,kBAAkB,CA6BpB;AAED,sEAAsE;AACtE,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,cAAc,GAAG,kBAAkB,CAUpF;AAQD;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,cAAc,EACnB,MAAM,CAAC,EAAE,MAAM,EACf,QAAQ,SAAI,GACX,KAAK,CAGP;AAED,mDAAmD;AACnD,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,QAAQ,EACd,GAAG,EAAE,cAAc,EACnB,QAAQ,SAAI,GACX,KAAK,CAGP;AAED,iEAAiE;AACjE,wBAAgB,eAAe,IAAI,QAAQ,CAE1C"}
|