@moltzap/client 2026.414.0 → 2026.425.1
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/dist/channel-core.d.ts +28 -15
- package/dist/channel-core.d.ts.map +1 -1
- package/dist/channel-core.js +113 -74
- package/dist/channel-core.js.map +1 -1
- package/dist/channel-core.test.js +126 -34
- package/dist/channel-core.test.js.map +1 -1
- package/dist/cli/__tests__/cli-multi-agent.int.test.d.ts +2 -0
- package/dist/cli/__tests__/cli-multi-agent.int.test.d.ts.map +1 -0
- package/dist/cli/__tests__/cli-multi-agent.int.test.js +26 -0
- package/dist/cli/__tests__/cli-multi-agent.int.test.js.map +1 -0
- package/dist/cli/commands/agents.d.ts +13 -2
- package/dist/cli/commands/agents.d.ts.map +1 -1
- package/dist/cli/commands/agents.js +30 -18
- package/dist/cli/commands/agents.js.map +1 -1
- package/dist/cli/commands/apps.d.ts +96 -0
- package/dist/cli/commands/apps.d.ts.map +1 -0
- package/dist/cli/commands/apps.js +193 -0
- package/dist/cli/commands/apps.js.map +1 -0
- package/dist/cli/commands/apps.test.d.ts +2 -0
- package/dist/cli/commands/apps.test.d.ts.map +1 -0
- package/dist/cli/commands/apps.test.js +220 -0
- package/dist/cli/commands/apps.test.js.map +1 -0
- package/dist/cli/commands/contacts.d.ts +18 -2
- package/dist/cli/commands/contacts.d.ts.map +1 -1
- package/dist/cli/commands/contacts.js +44 -52
- package/dist/cli/commands/contacts.js.map +1 -1
- package/dist/cli/commands/conversations-v2.test.d.ts +2 -0
- package/dist/cli/commands/conversations-v2.test.d.ts.map +1 -0
- package/dist/cli/commands/conversations-v2.test.js +92 -0
- package/dist/cli/commands/conversations-v2.test.js.map +1 -0
- package/dist/cli/commands/conversations.d.ts +73 -3
- package/dist/cli/commands/conversations.d.ts.map +1 -1
- package/dist/cli/commands/conversations.js +157 -108
- package/dist/cli/commands/conversations.js.map +1 -1
- package/dist/cli/commands/invite.d.ts +6 -2
- package/dist/cli/commands/invite.d.ts.map +1 -1
- package/dist/cli/commands/invite.js +8 -6
- package/dist/cli/commands/invite.js.map +1 -1
- package/dist/cli/commands/messages.d.ts +48 -0
- package/dist/cli/commands/messages.d.ts.map +1 -0
- package/dist/cli/commands/messages.js +68 -0
- package/dist/cli/commands/messages.js.map +1 -0
- package/dist/cli/commands/messages.test.d.ts +2 -0
- package/dist/cli/commands/messages.test.d.ts.map +1 -0
- package/dist/cli/commands/messages.test.js +73 -0
- package/dist/cli/commands/messages.test.js.map +1 -0
- package/dist/cli/commands/permissions.d.ts +66 -0
- package/dist/cli/commands/permissions.d.ts.map +1 -0
- package/dist/cli/commands/permissions.js +101 -0
- package/dist/cli/commands/permissions.js.map +1 -0
- package/dist/cli/commands/permissions.test.d.ts +2 -0
- package/dist/cli/commands/permissions.test.d.ts.map +1 -0
- package/dist/cli/commands/permissions.test.js +126 -0
- package/dist/cli/commands/permissions.test.js.map +1 -0
- package/dist/cli/commands/ping.d.ts +6 -2
- package/dist/cli/commands/ping.d.ts.map +1 -1
- package/dist/cli/commands/ping.js +21 -20
- package/dist/cli/commands/ping.js.map +1 -1
- package/dist/cli/commands/presence.d.ts +10 -2
- package/dist/cli/commands/presence.d.ts.map +1 -1
- package/dist/cli/commands/presence.js +27 -15
- package/dist/cli/commands/presence.js.map +1 -1
- package/dist/cli/commands/register.d.ts +24 -2
- package/dist/cli/commands/register.d.ts.map +1 -1
- package/dist/cli/commands/register.js +123 -47
- package/dist/cli/commands/register.js.map +1 -1
- package/dist/cli/commands/register.test.js +45 -27
- package/dist/cli/commands/register.test.js.map +1 -1
- package/dist/cli/commands/send.d.ts +43 -2
- package/dist/cli/commands/send.d.ts.map +1 -1
- package/dist/cli/commands/send.js +55 -13
- package/dist/cli/commands/send.js.map +1 -1
- package/dist/cli/commands/send.test.js +20 -19
- package/dist/cli/commands/send.test.js.map +1 -1
- package/dist/cli/commands/status.d.ts +6 -2
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +16 -10
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/whoami.d.ts +7 -2
- package/dist/cli/commands/whoami.d.ts.map +1 -1
- package/dist/cli/commands/whoami.js +13 -7
- package/dist/cli/commands/whoami.js.map +1 -1
- package/dist/cli/config.d.ts +24 -8
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +65 -39
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/config.test.js +12 -10
- package/dist/cli/config.test.js.map +1 -1
- package/dist/cli/http-client.d.ts +6 -2
- package/dist/cli/http-client.d.ts.map +1 -1
- package/dist/cli/http-client.js +25 -24
- package/dist/cli/http-client.js.map +1 -1
- package/dist/cli/index.d.ts +16 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +160 -27
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/profile.d.ts +134 -0
- package/dist/cli/profile.d.ts.map +1 -0
- package/dist/cli/profile.js +217 -0
- package/dist/cli/profile.js.map +1 -0
- package/dist/cli/profile.test.d.ts +2 -0
- package/dist/cli/profile.test.d.ts.map +1 -0
- package/dist/cli/profile.test.js +263 -0
- package/dist/cli/profile.test.js.map +1 -0
- package/dist/cli/runtime.d.ts +34 -0
- package/dist/cli/runtime.d.ts.map +1 -0
- package/dist/cli/runtime.js +94 -0
- package/dist/cli/runtime.js.map +1 -0
- package/dist/cli/socket-client.d.ts +15 -12
- package/dist/cli/socket-client.d.ts.map +1 -1
- package/dist/cli/socket-client.js +72 -75
- package/dist/cli/socket-client.js.map +1 -1
- package/dist/cli/transport.d.ts +181 -0
- package/dist/cli/transport.d.ts.map +1 -0
- package/dist/cli/transport.js +324 -0
- package/dist/cli/transport.js.map +1 -0
- package/dist/cli/transport.test.d.ts +2 -0
- package/dist/cli/transport.test.d.ts.map +1 -0
- package/dist/cli/transport.test.js +197 -0
- package/dist/cli/transport.test.js.map +1 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/runtime/close-info.d.ts +94 -0
- package/dist/runtime/close-info.d.ts.map +1 -0
- package/dist/runtime/close-info.js +109 -0
- package/dist/runtime/close-info.js.map +1 -0
- package/dist/runtime/close-info.test.d.ts +2 -0
- package/dist/runtime/close-info.test.d.ts.map +1 -0
- package/dist/runtime/close-info.test.js +102 -0
- package/dist/runtime/close-info.test.js.map +1 -0
- package/dist/runtime/errors.d.ts +47 -0
- package/dist/runtime/errors.d.ts.map +1 -0
- package/dist/runtime/errors.js +20 -0
- package/dist/runtime/errors.js.map +1 -0
- package/dist/runtime/errors.test.d.ts +2 -0
- package/dist/runtime/errors.test.d.ts.map +1 -0
- package/dist/runtime/errors.test.js +66 -0
- package/dist/runtime/errors.test.js.map +1 -0
- package/dist/runtime/frame.d.ts +25 -0
- package/dist/runtime/frame.d.ts.map +1 -0
- package/dist/runtime/frame.js +106 -0
- package/dist/runtime/frame.js.map +1 -0
- package/dist/runtime/frame.test.d.ts +2 -0
- package/dist/runtime/frame.test.d.ts.map +1 -0
- package/dist/runtime/frame.test.js +32 -0
- package/dist/runtime/frame.test.js.map +1 -0
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +3 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/refs.d.ts +10 -0
- package/dist/runtime/refs.d.ts.map +1 -0
- package/dist/runtime/refs.js +10 -0
- package/dist/runtime/refs.js.map +1 -0
- package/dist/runtime/runtime.test.d.ts +2 -0
- package/dist/runtime/runtime.test.d.ts.map +1 -0
- package/dist/runtime/runtime.test.js +29 -0
- package/dist/runtime/runtime.test.js.map +1 -0
- package/dist/runtime/subscribers.d.ts +157 -0
- package/dist/runtime/subscribers.d.ts.map +1 -0
- package/dist/runtime/subscribers.js +131 -0
- package/dist/runtime/subscribers.js.map +1 -0
- package/dist/runtime/subscribers.test.d.ts +2 -0
- package/dist/runtime/subscribers.test.d.ts.map +1 -0
- package/dist/runtime/subscribers.test.js +155 -0
- package/dist/runtime/subscribers.test.js.map +1 -0
- package/dist/service.d.ts +68 -17
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +461 -307
- package/dist/service.js.map +1 -1
- package/dist/service.test.js +266 -77
- package/dist/service.test.js.map +1 -1
- package/dist/test/index.d.ts +33 -0
- package/dist/test/index.d.ts.map +1 -0
- package/dist/test/index.js +44 -0
- package/dist/test/index.js.map +1 -0
- package/dist/test-utils/channel-service-fixture.d.ts +2 -1
- package/dist/test-utils/channel-service-fixture.d.ts.map +1 -1
- package/dist/test-utils/channel-service-fixture.js +31 -11
- package/dist/test-utils/channel-service-fixture.js.map +1 -1
- package/dist/test-utils/conformance-adapter.d.ts +50 -0
- package/dist/test-utils/conformance-adapter.d.ts.map +1 -0
- package/dist/test-utils/conformance-adapter.js +206 -0
- package/dist/test-utils/conformance-adapter.js.map +1 -0
- package/dist/test-utils/fake-service.d.ts +85 -0
- package/dist/test-utils/fake-service.d.ts.map +1 -0
- package/dist/test-utils/fake-service.js +103 -0
- package/dist/test-utils/fake-service.js.map +1 -0
- package/dist/test-utils/index.d.ts +2 -0
- package/dist/test-utils/index.d.ts.map +1 -1
- package/dist/test-utils/index.js +3 -2
- package/dist/test-utils/index.js.map +1 -1
- package/dist/ws-client.d.ts +157 -18
- package/dist/ws-client.d.ts.map +1 -1
- package/dist/ws-client.js +432 -94
- package/dist/ws-client.js.map +1 -1
- package/dist/ws-client.test.d.ts +2 -0
- package/dist/ws-client.test.d.ts.map +1 -0
- package/dist/ws-client.test.js +672 -0
- package/dist/ws-client.test.js.map +1 -0
- package/package.json +17 -8
- package/dist/__tests__/service.integration.test.d.ts +0 -2
- package/dist/__tests__/service.integration.test.d.ts.map +0 -1
- package/dist/__tests__/service.integration.test.js +0 -1087
- package/dist/__tests__/service.integration.test.js.map +0 -1
- package/dist/cli/commands/delete.d.ts +0 -3
- package/dist/cli/commands/delete.d.ts.map +0 -1
- package/dist/cli/commands/delete.js +0 -10
- package/dist/cli/commands/delete.js.map +0 -1
- package/dist/cli/commands/react.d.ts +0 -3
- package/dist/cli/commands/react.d.ts.map +0 -1
- package/dist/cli/commands/react.js +0 -18
- package/dist/cli/commands/react.js.map +0 -1
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
/**
|
|
3
|
+
* Branded profile name. Enforces the same NAME_PATTERN already gated by
|
|
4
|
+
* `commands/register.ts`: `/^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$/`.
|
|
5
|
+
*/
|
|
6
|
+
export type ProfileName = string & {
|
|
7
|
+
readonly __brand: "ProfileName";
|
|
8
|
+
};
|
|
9
|
+
/** Sentinel used when the caller addresses the legacy top-level record. */
|
|
10
|
+
export type DefaultProfileId = "default";
|
|
11
|
+
/**
|
|
12
|
+
* One profile's auth record. Shape mirrors the singleton's auth subset.
|
|
13
|
+
* `registeredAt` is OPTIONAL — legacy configs produced by pre-v2 `moltzap
|
|
14
|
+
* register` never wrote the field. The profile layer tolerates its absence
|
|
15
|
+
* so existing `~/.moltzap/config.json` files decode into `LayeredConfig`
|
|
16
|
+
* without rewrite (Invariant §4.3).
|
|
17
|
+
*/
|
|
18
|
+
export interface ProfileRecord {
|
|
19
|
+
readonly apiKey: string;
|
|
20
|
+
readonly agentName: string;
|
|
21
|
+
readonly serverUrl: string;
|
|
22
|
+
readonly registeredAt?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Layered view of config.json. The legacy top-level keys populate
|
|
26
|
+
* `default`; named records live under `profiles.<name>`. `serverUrl`
|
|
27
|
+
* is surfaced at the top because it is shared across profiles unless
|
|
28
|
+
* a profile overrides it.
|
|
29
|
+
*/
|
|
30
|
+
export interface LayeredConfig {
|
|
31
|
+
readonly default: ProfileRecord | undefined;
|
|
32
|
+
readonly profiles: ReadonlyMap<ProfileName, ProfileRecord>;
|
|
33
|
+
readonly serverUrl: string;
|
|
34
|
+
}
|
|
35
|
+
/** Exhaustive error union for the profile surface. */
|
|
36
|
+
export type ProfileError = ProfileNotFoundError | ProfileAlreadyExistsError | ProfileInvalidNameError | ProfileConfigReadError | ProfileConfigWriteError;
|
|
37
|
+
declare const ProfileNotFoundError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
38
|
+
readonly _tag: "ProfileNotFoundError";
|
|
39
|
+
} & Readonly<A>;
|
|
40
|
+
export declare class ProfileNotFoundError extends ProfileNotFoundError_base<{
|
|
41
|
+
readonly name: string;
|
|
42
|
+
}> {
|
|
43
|
+
}
|
|
44
|
+
declare const ProfileAlreadyExistsError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
45
|
+
readonly _tag: "ProfileAlreadyExistsError";
|
|
46
|
+
} & Readonly<A>;
|
|
47
|
+
export declare class ProfileAlreadyExistsError extends ProfileAlreadyExistsError_base<{
|
|
48
|
+
readonly name: string;
|
|
49
|
+
}> {
|
|
50
|
+
}
|
|
51
|
+
declare const ProfileInvalidNameError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
52
|
+
readonly _tag: "ProfileInvalidNameError";
|
|
53
|
+
} & Readonly<A>;
|
|
54
|
+
export declare class ProfileInvalidNameError extends ProfileInvalidNameError_base<{
|
|
55
|
+
readonly name: string;
|
|
56
|
+
readonly reason: string;
|
|
57
|
+
}> {
|
|
58
|
+
}
|
|
59
|
+
declare const ProfileConfigReadError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
60
|
+
readonly _tag: "ProfileConfigReadError";
|
|
61
|
+
} & Readonly<A>;
|
|
62
|
+
export declare class ProfileConfigReadError extends ProfileConfigReadError_base<{
|
|
63
|
+
readonly path: string;
|
|
64
|
+
readonly cause: unknown;
|
|
65
|
+
}> {
|
|
66
|
+
}
|
|
67
|
+
declare const ProfileConfigWriteError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
68
|
+
readonly _tag: "ProfileConfigWriteError";
|
|
69
|
+
} & Readonly<A>;
|
|
70
|
+
export declare class ProfileConfigWriteError extends ProfileConfigWriteError_base<{
|
|
71
|
+
readonly path: string;
|
|
72
|
+
readonly cause: unknown;
|
|
73
|
+
}> {
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Parse and brand a raw profile name. Rejects the empty string and any
|
|
77
|
+
* string that fails NAME_PATTERN.
|
|
78
|
+
*/
|
|
79
|
+
export declare const parseProfileName: (raw: string) => Effect.Effect<ProfileName, ProfileInvalidNameError>;
|
|
80
|
+
/**
|
|
81
|
+
* Load the full layered config view. Missing file resolves to an empty
|
|
82
|
+
* view; malformed file surfaces as ProfileConfigReadError. No silent
|
|
83
|
+
* defaults on parse error.
|
|
84
|
+
*
|
|
85
|
+
* Unknown-key tolerance: the decoder accepts extra top-level keys (e.g.
|
|
86
|
+
* future experimental fields) without failing. This keeps forward and
|
|
87
|
+
* backward compatibility explicit rather than implicit.
|
|
88
|
+
*/
|
|
89
|
+
export declare const loadLayeredConfig: Effect.Effect<LayeredConfig, ProfileConfigReadError>;
|
|
90
|
+
/**
|
|
91
|
+
* Resolve the auth record for a given profile name.
|
|
92
|
+
*
|
|
93
|
+
* When `name` is `undefined`, the `default` record is returned (legacy
|
|
94
|
+
* behavior for users who never pass `--profile`). When `name` is supplied
|
|
95
|
+
* and no matching record exists, fails with ProfileNotFoundError — do not
|
|
96
|
+
* silently fall back to `default`; that would violate Invariant §4.3's
|
|
97
|
+
* "takes precedence" clause in the opposite direction.
|
|
98
|
+
*/
|
|
99
|
+
export declare const resolveProfileAuth: (name: ProfileName | undefined) => Effect.Effect<ProfileRecord, ProfileNotFoundError | ProfileConfigReadError>;
|
|
100
|
+
/**
|
|
101
|
+
* Persist a new profile record under `profiles.<name>`, or replace the
|
|
102
|
+
* legacy top-level record when `name` is `"default"`.
|
|
103
|
+
*
|
|
104
|
+
* When called with `"default"`, writes the legacy top-level `apiKey` /
|
|
105
|
+
* `agentName` fields (not under `profiles`) so pre-profile-aware readers
|
|
106
|
+
* keep working (Invariant §4.3).
|
|
107
|
+
*/
|
|
108
|
+
export declare const writeProfile: (name: ProfileName | DefaultProfileId, record: ProfileRecord) => Effect.Effect<void, ProfileConfigWriteError | ProfileConfigReadError>;
|
|
109
|
+
/**
|
|
110
|
+
* `--no-persist` contract for `moltzap register`. Revised Invariant §4.4
|
|
111
|
+
* per architect design doc rev 4 finding 2: no file under `$HOME/.moltzap/`
|
|
112
|
+
* OR `$HOME/.openclaw/` is created or modified. Returns the record so the
|
|
113
|
+
* caller can print it; does no I/O under either tree.
|
|
114
|
+
*
|
|
115
|
+
* The register command invokes either `writeProfile` + the existing
|
|
116
|
+
* `writeOpenClawChannelConfig` (default) or `emitNoPersist` (when the flag
|
|
117
|
+
* is set) — both side effects are gated by the single flag. The register
|
|
118
|
+
* handler NEVER calls both paths on the same invocation.
|
|
119
|
+
*
|
|
120
|
+
* The register command pipes the returned record through the printer,
|
|
121
|
+
* which writes agentId / apiKey / serverUrl / claimUrl to stdout (so
|
|
122
|
+
* callers can `$(moltzap register --no-persist ...)` into env).
|
|
123
|
+
*/
|
|
124
|
+
export declare const emitNoPersist: (record: ProfileRecord) => Effect.Effect<{
|
|
125
|
+
readonly record: ProfileRecord;
|
|
126
|
+
}, never>;
|
|
127
|
+
/**
|
|
128
|
+
* Absolute path to the config file. Overridable at test time via the
|
|
129
|
+
* `MOLTZAP_CONFIG_HOME` env (tests set a tmp dir; production leaves unset).
|
|
130
|
+
* Exported so assertions can diff the file after a command run.
|
|
131
|
+
*/
|
|
132
|
+
export declare const getConfigFilePath: Effect.Effect<string, never>;
|
|
133
|
+
export {};
|
|
134
|
+
//# sourceMappingURL=profile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../../src/cli/profile.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAQ,MAAM,EAAE,MAAM,QAAQ,CAAC;AAItC;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAA;CAAE,CAAC;AAEvE,2EAA2E;AAC3E,MAAM,MAAM,gBAAgB,GAAG,SAAS,CAAC;AAczC;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,aAAa,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAC3D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAID,sDAAsD;AACtD,MAAM,MAAM,YAAY,GACpB,oBAAoB,GACpB,yBAAyB,GACzB,uBAAuB,GACvB,sBAAsB,GACtB,uBAAuB,CAAC;;;;AAE5B,qBAAa,oBAAqB,SAAQ,0BAExC;IACA,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;CAAG;;;;AAEL,qBAAa,yBAA0B,SAAQ,+BAE7C;IACA,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;CAAG;;;;AAEL,qBAAa,uBAAwB,SAAQ,6BAE3C;IACA,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;CAAG;;;;AAEL,qBAAa,sBAAuB,SAAQ,4BAE1C;IACA,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB,CAAC;CAAG;;;;AAEL,qBAAa,uBAAwB,SAAQ,6BAE3C;IACA,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB,CAAC;CAAG;AAIL;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAC3B,KAAK,MAAM,KACV,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,uBAAuB,CAgBpD,CAAC;AA4DF;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,CAC3C,aAAa,EACb,sBAAsB,CA2BtB,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAC7B,MAAM,WAAW,GAAG,SAAS,KAC5B,MAAM,CAAC,MAAM,CACd,aAAa,EACb,oBAAoB,GAAG,sBAAsB,CAiB3C,CAAC;AAEL;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,GACvB,MAAM,WAAW,GAAG,gBAAgB,EACpC,QAAQ,aAAa,KACpB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,uBAAuB,GAAG,sBAAsB,CAsCnE,CAAC;AAEL;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,aAAa,GACxB,QAAQ,aAAa,KACpB,MAAM,CAAC,MAAM,CAAC;IAAE,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAA;CAAE,EAAE,KAAK,CAC9B,CAAC;AAI7B;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAE1D,CAAC"}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile layer over `~/.moltzap/config.json`.
|
|
3
|
+
*
|
|
4
|
+
* Backward-compatible extension of the existing singleton: the top-level
|
|
5
|
+
* `apiKey` / `agentName` fields (see cli/config.ts) remain the "default"
|
|
6
|
+
* record; named profiles live under a new top-level `profiles` key.
|
|
7
|
+
*
|
|
8
|
+
* Spec sbd#177 rev 3 §5.2 (`--profile <name>`, `--no-persist`),
|
|
9
|
+
* Invariants §4.3 (coexistence) and §4.4 (no-disk-write guarantee).
|
|
10
|
+
*
|
|
11
|
+
* Architect note. The existing `cli/config.ts` pre-dates this branch and is
|
|
12
|
+
* not edited here (architect rule: no edits to pre-dating files beyond one
|
|
13
|
+
* barrel). `loadLayeredConfig` therefore reads the file directly for the
|
|
14
|
+
* profile-aware path; impl-staff may collapse this back into `config.ts`
|
|
15
|
+
* during implementation, at which point the profile module becomes a
|
|
16
|
+
* named export of `config.ts`. The public interface defined below is the
|
|
17
|
+
* contract impl-staff preserves regardless of layout.
|
|
18
|
+
*/
|
|
19
|
+
import * as fs from "node:fs";
|
|
20
|
+
import * as os from "node:os";
|
|
21
|
+
import * as path from "node:path";
|
|
22
|
+
import { Data, Effect } from "effect";
|
|
23
|
+
const NAME_PATTERN = /^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$/;
|
|
24
|
+
const DEFAULT_SERVER_URL = "wss://api.moltzap.xyz";
|
|
25
|
+
const getConfigDir = () => process.env.MOLTZAP_CONFIG_HOME ?? path.join(os.homedir(), ".moltzap");
|
|
26
|
+
const getConfigFilePathSync = () => path.join(getConfigDir(), "config.json");
|
|
27
|
+
export class ProfileNotFoundError extends Data.TaggedError("ProfileNotFoundError") {
|
|
28
|
+
}
|
|
29
|
+
export class ProfileAlreadyExistsError extends Data.TaggedError("ProfileAlreadyExistsError") {
|
|
30
|
+
}
|
|
31
|
+
export class ProfileInvalidNameError extends Data.TaggedError("ProfileInvalidNameError") {
|
|
32
|
+
}
|
|
33
|
+
export class ProfileConfigReadError extends Data.TaggedError("ProfileConfigReadError") {
|
|
34
|
+
}
|
|
35
|
+
export class ProfileConfigWriteError extends Data.TaggedError("ProfileConfigWriteError") {
|
|
36
|
+
}
|
|
37
|
+
// ─── Public API ────────────────────────────────────────────────────────────
|
|
38
|
+
/**
|
|
39
|
+
* Parse and brand a raw profile name. Rejects the empty string and any
|
|
40
|
+
* string that fails NAME_PATTERN.
|
|
41
|
+
*/
|
|
42
|
+
export const parseProfileName = (raw) => {
|
|
43
|
+
if (raw.length === 0) {
|
|
44
|
+
return Effect.fail(new ProfileInvalidNameError({ name: raw, reason: "empty string" }));
|
|
45
|
+
}
|
|
46
|
+
if (!NAME_PATTERN.test(raw)) {
|
|
47
|
+
return Effect.fail(new ProfileInvalidNameError({
|
|
48
|
+
name: raw,
|
|
49
|
+
reason: "must be 3-32 chars, lowercase alphanumeric and hyphens, cannot start or end with a hyphen",
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
return Effect.succeed(raw);
|
|
53
|
+
};
|
|
54
|
+
const isRecord = (x) => typeof x === "object" && x !== null && !Array.isArray(x);
|
|
55
|
+
const decodeProfileRecord = (raw, fallbackServerUrl) => {
|
|
56
|
+
if (!isRecord(raw))
|
|
57
|
+
return undefined;
|
|
58
|
+
const apiKey = raw.apiKey;
|
|
59
|
+
const agentName = raw.agentName;
|
|
60
|
+
if (typeof apiKey !== "string" || typeof agentName !== "string") {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
const serverUrl = typeof raw.serverUrl === "string" ? raw.serverUrl : fallbackServerUrl;
|
|
64
|
+
const record = { apiKey, agentName, serverUrl };
|
|
65
|
+
if (typeof raw.registeredAt === "string") {
|
|
66
|
+
return { ...record, registeredAt: raw.registeredAt };
|
|
67
|
+
}
|
|
68
|
+
return record;
|
|
69
|
+
};
|
|
70
|
+
const readRawConfig = () => Effect.try({
|
|
71
|
+
try: () => {
|
|
72
|
+
const p = getConfigFilePathSync();
|
|
73
|
+
try {
|
|
74
|
+
const text = fs.readFileSync(p, "utf-8");
|
|
75
|
+
const parsed = JSON.parse(text);
|
|
76
|
+
if (!isRecord(parsed)) {
|
|
77
|
+
throw new Error("config root is not a JSON object");
|
|
78
|
+
}
|
|
79
|
+
return { raw: parsed, existed: true };
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
const code = err.code;
|
|
83
|
+
if (code === "ENOENT") {
|
|
84
|
+
return { raw: {}, existed: false };
|
|
85
|
+
}
|
|
86
|
+
throw err;
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
catch: (err) => new ProfileConfigReadError({
|
|
90
|
+
path: getConfigFilePathSync(),
|
|
91
|
+
cause: err,
|
|
92
|
+
}),
|
|
93
|
+
});
|
|
94
|
+
/**
|
|
95
|
+
* Load the full layered config view. Missing file resolves to an empty
|
|
96
|
+
* view; malformed file surfaces as ProfileConfigReadError. No silent
|
|
97
|
+
* defaults on parse error.
|
|
98
|
+
*
|
|
99
|
+
* Unknown-key tolerance: the decoder accepts extra top-level keys (e.g.
|
|
100
|
+
* future experimental fields) without failing. This keeps forward and
|
|
101
|
+
* backward compatibility explicit rather than implicit.
|
|
102
|
+
*/
|
|
103
|
+
export const loadLayeredConfig = Effect.gen(function* () {
|
|
104
|
+
const { raw } = yield* readRawConfig();
|
|
105
|
+
const serverUrl = typeof raw.serverUrl === "string" ? raw.serverUrl : DEFAULT_SERVER_URL;
|
|
106
|
+
let defaultRecord;
|
|
107
|
+
if (typeof raw.apiKey === "string" && typeof raw.agentName === "string") {
|
|
108
|
+
defaultRecord = {
|
|
109
|
+
apiKey: raw.apiKey,
|
|
110
|
+
agentName: raw.agentName,
|
|
111
|
+
serverUrl,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const profiles = new Map();
|
|
115
|
+
if (isRecord(raw.profiles)) {
|
|
116
|
+
for (const [name, value] of Object.entries(raw.profiles)) {
|
|
117
|
+
if (!NAME_PATTERN.test(name))
|
|
118
|
+
continue; // tolerate malformed entries
|
|
119
|
+
const record = decodeProfileRecord(value, serverUrl);
|
|
120
|
+
if (record !== undefined) {
|
|
121
|
+
profiles.set(name, record);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return { default: defaultRecord, profiles, serverUrl };
|
|
126
|
+
});
|
|
127
|
+
/**
|
|
128
|
+
* Resolve the auth record for a given profile name.
|
|
129
|
+
*
|
|
130
|
+
* When `name` is `undefined`, the `default` record is returned (legacy
|
|
131
|
+
* behavior for users who never pass `--profile`). When `name` is supplied
|
|
132
|
+
* and no matching record exists, fails with ProfileNotFoundError — do not
|
|
133
|
+
* silently fall back to `default`; that would violate Invariant §4.3's
|
|
134
|
+
* "takes precedence" clause in the opposite direction.
|
|
135
|
+
*/
|
|
136
|
+
export const resolveProfileAuth = (name) => Effect.gen(function* () {
|
|
137
|
+
const layered = yield* loadLayeredConfig;
|
|
138
|
+
if (name === undefined) {
|
|
139
|
+
if (layered.default === undefined) {
|
|
140
|
+
return yield* Effect.fail(new ProfileNotFoundError({ name: "default" }));
|
|
141
|
+
}
|
|
142
|
+
return layered.default;
|
|
143
|
+
}
|
|
144
|
+
const found = layered.profiles.get(name);
|
|
145
|
+
if (found === undefined) {
|
|
146
|
+
return yield* Effect.fail(new ProfileNotFoundError({ name }));
|
|
147
|
+
}
|
|
148
|
+
return found;
|
|
149
|
+
});
|
|
150
|
+
/**
|
|
151
|
+
* Persist a new profile record under `profiles.<name>`, or replace the
|
|
152
|
+
* legacy top-level record when `name` is `"default"`.
|
|
153
|
+
*
|
|
154
|
+
* When called with `"default"`, writes the legacy top-level `apiKey` /
|
|
155
|
+
* `agentName` fields (not under `profiles`) so pre-profile-aware readers
|
|
156
|
+
* keep working (Invariant §4.3).
|
|
157
|
+
*/
|
|
158
|
+
export const writeProfile = (name, record) => Effect.gen(function* () {
|
|
159
|
+
const { raw } = yield* readRawConfig();
|
|
160
|
+
const next = { ...raw };
|
|
161
|
+
if (name === "default") {
|
|
162
|
+
next.serverUrl = record.serverUrl;
|
|
163
|
+
next.apiKey = record.apiKey;
|
|
164
|
+
next.agentName = record.agentName;
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
const existingProfiles = isRecord(next.profiles) ? next.profiles : {};
|
|
168
|
+
const profileBody = {
|
|
169
|
+
apiKey: record.apiKey,
|
|
170
|
+
agentName: record.agentName,
|
|
171
|
+
serverUrl: record.serverUrl,
|
|
172
|
+
};
|
|
173
|
+
if (record.registeredAt !== undefined) {
|
|
174
|
+
profileBody.registeredAt = record.registeredAt;
|
|
175
|
+
}
|
|
176
|
+
next.profiles = { ...existingProfiles, [name]: profileBody };
|
|
177
|
+
// serverUrl at top level stays as-is for legacy readers.
|
|
178
|
+
if (typeof next.serverUrl !== "string") {
|
|
179
|
+
next.serverUrl = record.serverUrl;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const configDir = getConfigDir();
|
|
183
|
+
const configPath = getConfigFilePathSync();
|
|
184
|
+
yield* Effect.try({
|
|
185
|
+
try: () => {
|
|
186
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
187
|
+
fs.writeFileSync(configPath, JSON.stringify(next, null, 2) + "\n", {
|
|
188
|
+
mode: 0o600,
|
|
189
|
+
});
|
|
190
|
+
},
|
|
191
|
+
catch: (err) => new ProfileConfigWriteError({ path: configPath, cause: err }),
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
/**
|
|
195
|
+
* `--no-persist` contract for `moltzap register`. Revised Invariant §4.4
|
|
196
|
+
* per architect design doc rev 4 finding 2: no file under `$HOME/.moltzap/`
|
|
197
|
+
* OR `$HOME/.openclaw/` is created or modified. Returns the record so the
|
|
198
|
+
* caller can print it; does no I/O under either tree.
|
|
199
|
+
*
|
|
200
|
+
* The register command invokes either `writeProfile` + the existing
|
|
201
|
+
* `writeOpenClawChannelConfig` (default) or `emitNoPersist` (when the flag
|
|
202
|
+
* is set) — both side effects are gated by the single flag. The register
|
|
203
|
+
* handler NEVER calls both paths on the same invocation.
|
|
204
|
+
*
|
|
205
|
+
* The register command pipes the returned record through the printer,
|
|
206
|
+
* which writes agentId / apiKey / serverUrl / claimUrl to stdout (so
|
|
207
|
+
* callers can `$(moltzap register --no-persist ...)` into env).
|
|
208
|
+
*/
|
|
209
|
+
export const emitNoPersist = (record) => Effect.succeed({ record });
|
|
210
|
+
// ─── Test seam ─────────────────────────────────────────────────────────────
|
|
211
|
+
/**
|
|
212
|
+
* Absolute path to the config file. Overridable at test time via the
|
|
213
|
+
* `MOLTZAP_CONFIG_HOME` env (tests set a tmp dir; production leaves unset).
|
|
214
|
+
* Exported so assertions can diff the file after a command run.
|
|
215
|
+
*/
|
|
216
|
+
export const getConfigFilePath = Effect.sync(() => getConfigFilePathSync());
|
|
217
|
+
//# sourceMappingURL=profile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.js","sourceRoot":"","sources":["../../src/cli/profile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.test.d.ts","sourceRoot":"","sources":["../../src/cli/profile.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for the profile layer. Spec items §5.2 (`--profile`,
|
|
3
|
+
* `--no-persist`), Invariants §4.3 (coexistence), §4.4 (no-disk-write).
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from "node:fs";
|
|
6
|
+
import * as path from "node:path";
|
|
7
|
+
import * as os from "node:os";
|
|
8
|
+
import { Effect } from "effect";
|
|
9
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
10
|
+
import { emitNoPersist, loadLayeredConfig, parseProfileName, ProfileInvalidNameError, ProfileNotFoundError, resolveProfileAuth, writeProfile, } from "./profile.js";
|
|
11
|
+
/**
|
|
12
|
+
* Helper: create a temp dir, point MOLTZAP_CONFIG_HOME at it for the
|
|
13
|
+
* duration of a test, seed with optional JSON, run fn, clean up.
|
|
14
|
+
*/
|
|
15
|
+
const withTmpConfigHome = async (seed, fn) => {
|
|
16
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "moltzap-profile-"));
|
|
17
|
+
const originalHome = process.env.MOLTZAP_CONFIG_HOME;
|
|
18
|
+
process.env.MOLTZAP_CONFIG_HOME = tmp;
|
|
19
|
+
try {
|
|
20
|
+
if (seed !== undefined) {
|
|
21
|
+
fs.writeFileSync(path.join(tmp, "config.json"), JSON.stringify(seed, null, 2));
|
|
22
|
+
}
|
|
23
|
+
return await fn(tmp);
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
if (originalHome === undefined) {
|
|
27
|
+
delete process.env.MOLTZAP_CONFIG_HOME;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
process.env.MOLTZAP_CONFIG_HOME = originalHome;
|
|
31
|
+
}
|
|
32
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
describe("parseProfileName", () => {
|
|
36
|
+
it("accepts a valid lowercase-alphanumeric name", async () => {
|
|
37
|
+
const name = await Effect.runPromise(parseProfileName("alice-bot"));
|
|
38
|
+
expect(name).toBe("alice-bot");
|
|
39
|
+
});
|
|
40
|
+
it("rejects an empty string with ProfileInvalidNameError", async () => {
|
|
41
|
+
const exit = await Effect.runPromiseExit(parseProfileName(""));
|
|
42
|
+
expect(exit._tag).toBe("Failure");
|
|
43
|
+
});
|
|
44
|
+
it("rejects a name with uppercase letters", async () => {
|
|
45
|
+
const exit = await Effect.runPromiseExit(parseProfileName("Alice"));
|
|
46
|
+
expect(exit._tag).toBe("Failure");
|
|
47
|
+
});
|
|
48
|
+
it("rejects a name starting with a hyphen", async () => {
|
|
49
|
+
const exit = await Effect.runPromiseExit(parseProfileName("-alice"));
|
|
50
|
+
expect(exit._tag).toBe("Failure");
|
|
51
|
+
});
|
|
52
|
+
it("rejects a name ending with a hyphen", async () => {
|
|
53
|
+
const exit = await Effect.runPromiseExit(parseProfileName("alice-"));
|
|
54
|
+
expect(exit._tag).toBe("Failure");
|
|
55
|
+
});
|
|
56
|
+
it("fails with ProfileInvalidNameError type", async () => {
|
|
57
|
+
const exit = await Effect.runPromiseExit(parseProfileName(""));
|
|
58
|
+
if (exit._tag === "Failure") {
|
|
59
|
+
const s = JSON.stringify(exit.cause);
|
|
60
|
+
expect(s).toMatch(/ProfileInvalidNameError/);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
describe("loadLayeredConfig", () => {
|
|
65
|
+
it("missing file resolves with empty view (default undefined, empty profiles)", async () => {
|
|
66
|
+
await withTmpConfigHome(undefined, async () => {
|
|
67
|
+
const view = await Effect.runPromise(loadLayeredConfig);
|
|
68
|
+
expect(view.default).toBeUndefined();
|
|
69
|
+
expect(view.profiles.size).toBe(0);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
it("legacy top-level { apiKey, agentName } populates default", async () => {
|
|
73
|
+
await withTmpConfigHome({
|
|
74
|
+
serverUrl: "wss://x",
|
|
75
|
+
apiKey: "k1",
|
|
76
|
+
agentName: "a1",
|
|
77
|
+
}, async () => {
|
|
78
|
+
const view = await Effect.runPromise(loadLayeredConfig);
|
|
79
|
+
expect(view.default?.apiKey).toBe("k1");
|
|
80
|
+
expect(view.default?.agentName).toBe("a1");
|
|
81
|
+
expect(view.serverUrl).toBe("wss://x");
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
it("{ profiles: { alice: ... } } populates the profiles map", async () => {
|
|
85
|
+
await withTmpConfigHome({
|
|
86
|
+
serverUrl: "wss://x",
|
|
87
|
+
profiles: {
|
|
88
|
+
alice: {
|
|
89
|
+
apiKey: "k-alice",
|
|
90
|
+
agentName: "alice",
|
|
91
|
+
serverUrl: "wss://x",
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
}, async () => {
|
|
95
|
+
const view = await Effect.runPromise(loadLayeredConfig);
|
|
96
|
+
expect(view.profiles.size).toBe(1);
|
|
97
|
+
const rec = view.profiles.get("alice");
|
|
98
|
+
expect(rec?.apiKey).toBe("k-alice");
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
it("tolerates unknown top-level keys", async () => {
|
|
102
|
+
await withTmpConfigHome({
|
|
103
|
+
serverUrl: "wss://x",
|
|
104
|
+
apiKey: "k",
|
|
105
|
+
agentName: "a",
|
|
106
|
+
// future-experimental key; should not cause a parse failure.
|
|
107
|
+
futureExperimentalField: { nested: true },
|
|
108
|
+
}, async () => {
|
|
109
|
+
const view = await Effect.runPromise(loadLayeredConfig);
|
|
110
|
+
expect(view.default?.apiKey).toBe("k");
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
it("missing registeredAt on legacy-shaped profile still decodes", async () => {
|
|
114
|
+
await withTmpConfigHome({
|
|
115
|
+
serverUrl: "wss://x",
|
|
116
|
+
profiles: {
|
|
117
|
+
bob: { apiKey: "k-bob", agentName: "bob", serverUrl: "wss://x" },
|
|
118
|
+
},
|
|
119
|
+
}, async () => {
|
|
120
|
+
const view = await Effect.runPromise(loadLayeredConfig);
|
|
121
|
+
const rec = view.profiles.get("bob");
|
|
122
|
+
expect(rec?.registeredAt).toBeUndefined();
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
it("parse error surfaces as ProfileConfigReadError (no silent defaults)", async () => {
|
|
126
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "moltzap-profile-"));
|
|
127
|
+
const originalHome = process.env.MOLTZAP_CONFIG_HOME;
|
|
128
|
+
process.env.MOLTZAP_CONFIG_HOME = tmp;
|
|
129
|
+
try {
|
|
130
|
+
fs.writeFileSync(path.join(tmp, "config.json"), "{not json}");
|
|
131
|
+
const exit = await Effect.runPromiseExit(loadLayeredConfig);
|
|
132
|
+
expect(exit._tag).toBe("Failure");
|
|
133
|
+
if (exit._tag === "Failure") {
|
|
134
|
+
const s = JSON.stringify(exit.cause);
|
|
135
|
+
expect(s).toMatch(/ProfileConfigReadError/);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
if (originalHome === undefined) {
|
|
140
|
+
delete process.env.MOLTZAP_CONFIG_HOME;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
process.env.MOLTZAP_CONFIG_HOME = originalHome;
|
|
144
|
+
}
|
|
145
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
describe("resolveProfileAuth", () => {
|
|
150
|
+
it("undefined name returns the default record", async () => {
|
|
151
|
+
await withTmpConfigHome({ serverUrl: "wss://x", apiKey: "k", agentName: "a" }, async () => {
|
|
152
|
+
const record = await Effect.runPromise(resolveProfileAuth(undefined));
|
|
153
|
+
expect(record.apiKey).toBe("k");
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
it("unknown name returns ProfileNotFoundError (no fallback to default)", async () => {
|
|
157
|
+
await withTmpConfigHome({ serverUrl: "wss://x", apiKey: "k", agentName: "a" }, async () => {
|
|
158
|
+
const exit = await Effect.runPromiseExit(resolveProfileAuth("ghost"));
|
|
159
|
+
expect(exit._tag).toBe("Failure");
|
|
160
|
+
if (exit._tag === "Failure") {
|
|
161
|
+
const s = JSON.stringify(exit.cause);
|
|
162
|
+
expect(s).toMatch(/ProfileNotFoundError/);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
it("known name returns the named record", async () => {
|
|
167
|
+
await withTmpConfigHome({
|
|
168
|
+
serverUrl: "wss://x",
|
|
169
|
+
profiles: {
|
|
170
|
+
alice: {
|
|
171
|
+
apiKey: "k-alice",
|
|
172
|
+
agentName: "alice",
|
|
173
|
+
serverUrl: "wss://x",
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
}, async () => {
|
|
177
|
+
const record = await Effect.runPromise(resolveProfileAuth("alice"));
|
|
178
|
+
expect(record.apiKey).toBe("k-alice");
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
it("ProfileNotFoundError carries the requested name", () => {
|
|
182
|
+
const err = new ProfileNotFoundError({ name: "nobody" });
|
|
183
|
+
expect(err.name).toBe("nobody");
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
describe("writeProfile", () => {
|
|
187
|
+
it("writing under a named profile leaves top-level apiKey untouched", async () => {
|
|
188
|
+
await withTmpConfigHome({ serverUrl: "wss://x", apiKey: "legacy-key", agentName: "legacy" }, async (tmp) => {
|
|
189
|
+
await Effect.runPromise(writeProfile("alice", {
|
|
190
|
+
apiKey: "k-alice",
|
|
191
|
+
agentName: "alice",
|
|
192
|
+
serverUrl: "wss://x",
|
|
193
|
+
}));
|
|
194
|
+
const written = JSON.parse(fs.readFileSync(path.join(tmp, "config.json"), "utf-8"));
|
|
195
|
+
expect(written.apiKey).toBe("legacy-key");
|
|
196
|
+
expect(written.profiles.alice.apiKey).toBe("k-alice");
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
it("writing 'default' updates top-level keys (not under profiles)", async () => {
|
|
200
|
+
await withTmpConfigHome(undefined, async (tmp) => {
|
|
201
|
+
await Effect.runPromise(writeProfile("default", {
|
|
202
|
+
apiKey: "k",
|
|
203
|
+
agentName: "a",
|
|
204
|
+
serverUrl: "wss://x",
|
|
205
|
+
}));
|
|
206
|
+
const written = JSON.parse(fs.readFileSync(path.join(tmp, "config.json"), "utf-8"));
|
|
207
|
+
expect(written.apiKey).toBe("k");
|
|
208
|
+
expect(written.profiles).toBeUndefined();
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
it("adding a second profile preserves the first", async () => {
|
|
212
|
+
await withTmpConfigHome({
|
|
213
|
+
serverUrl: "wss://x",
|
|
214
|
+
profiles: {
|
|
215
|
+
alice: {
|
|
216
|
+
apiKey: "k-alice",
|
|
217
|
+
agentName: "alice",
|
|
218
|
+
serverUrl: "wss://x",
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
}, async (tmp) => {
|
|
222
|
+
await Effect.runPromise(writeProfile("bob", {
|
|
223
|
+
apiKey: "k-bob",
|
|
224
|
+
agentName: "bob",
|
|
225
|
+
serverUrl: "wss://x",
|
|
226
|
+
}));
|
|
227
|
+
const written = JSON.parse(fs.readFileSync(path.join(tmp, "config.json"), "utf-8"));
|
|
228
|
+
expect(written.profiles.alice.apiKey).toBe("k-alice");
|
|
229
|
+
expect(written.profiles.bob.apiKey).toBe("k-bob");
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
describe("emitNoPersist", () => {
|
|
234
|
+
it("never writes to ~/.moltzap/ (fs diff before/after is empty)", async () => {
|
|
235
|
+
await withTmpConfigHome(undefined, async (tmp) => {
|
|
236
|
+
const before = fs.readdirSync(tmp);
|
|
237
|
+
await Effect.runPromise(emitNoPersist({
|
|
238
|
+
apiKey: "k",
|
|
239
|
+
agentName: "a",
|
|
240
|
+
serverUrl: "wss://x",
|
|
241
|
+
}));
|
|
242
|
+
const after = fs.readdirSync(tmp);
|
|
243
|
+
expect(after).toEqual(before);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
it("returns the record unchanged for the caller to print", async () => {
|
|
247
|
+
const record = {
|
|
248
|
+
apiKey: "k",
|
|
249
|
+
agentName: "a",
|
|
250
|
+
serverUrl: "wss://x",
|
|
251
|
+
};
|
|
252
|
+
const result = await Effect.runPromise(emitNoPersist(record));
|
|
253
|
+
expect(result.record).toEqual(record);
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
describe("ProfileInvalidNameError", () => {
|
|
257
|
+
it("carries name and reason", () => {
|
|
258
|
+
const err = new ProfileInvalidNameError({ name: "Bad", reason: "upper" });
|
|
259
|
+
expect(err.name).toBe("Bad");
|
|
260
|
+
expect(err.reason).toBe("upper");
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
//# sourceMappingURL=profile.test.js.map
|