@m1a0rz/agent-identity 0.5.0 → 0.5.2
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/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +35 -10
- package/dist/src/local-server/handlers.d.ts.map +1 -1
- package/dist/src/local-server/handlers.js +6 -1
- package/dist/src/local-server/peer-check.d.ts.map +1 -1
- package/dist/src/local-server/peer-check.js +1 -2
- package/dist/src/preflight/plugin-preflight.d.ts +9 -0
- package/dist/src/preflight/plugin-preflight.d.ts.map +1 -1
- package/dist/src/preflight/plugin-preflight.js +22 -8
- package/dist/src/preflight/plugin-state.d.ts.map +1 -1
- package/dist/src/preflight/plugin-state.js +10 -4
- package/dist/src/services/identity-credentials.d.ts.map +1 -1
- package/dist/src/services/identity-credentials.js +1 -23
- package/dist/src/store/encryption.d.ts.map +1 -1
- package/dist/src/store/encryption.js +15 -11
- package/package.json +10 -2
package/dist/index.d.ts
CHANGED
|
@@ -10,5 +10,7 @@
|
|
|
10
10
|
* - Tools: identity_whoami, identity_logout
|
|
11
11
|
*/
|
|
12
12
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
13
|
-
|
|
13
|
+
declare function registerImpl(api: OpenClawPluginApi): void;
|
|
14
|
+
declare const _default: typeof registerImpl;
|
|
15
|
+
export default _default;
|
|
14
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAgB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAgB,MAAM,qBAAqB,CAAC;AAkG3E,iBAAS,YAAY,CAAC,GAAG,EAAE,iBAAiB,QAqjB3C;wBAMwC,OAAO,YAAY;AAA5D,wBAA6D"}
|
package/dist/index.js
CHANGED
|
@@ -75,7 +75,19 @@ function hasAnyIdentityConfig(identity) {
|
|
|
75
75
|
identity.audience?.length ||
|
|
76
76
|
identity.durationSeconds);
|
|
77
77
|
}
|
|
78
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Guard against jiti module duplication.
|
|
80
|
+
*
|
|
81
|
+
* OpenClaw ≥ v2026.3.28 may create multiple jiti instances with independent
|
|
82
|
+
* module caches. If this file is loaded twice, module-level state (Maps,
|
|
83
|
+
* flags, cached promises) in transitive imports splits into two copies and
|
|
84
|
+
* silently diverges. By pinning the register function on globalThis, the
|
|
85
|
+
* second load re-exports the first load's function, whose closures reference
|
|
86
|
+
* the first module graph — keeping all 27+ mutable module-level variables in
|
|
87
|
+
* a single, consistent copy.
|
|
88
|
+
*/
|
|
89
|
+
const PLUGIN_REGISTER_KEY = Symbol.for("openclaw-identity.pluginRegister");
|
|
90
|
+
function registerImpl(api) {
|
|
79
91
|
const pluginConfig = (api.pluginConfig ?? {});
|
|
80
92
|
const storeDir = api.resolvePath(PLUGIN_STORE_DIR);
|
|
81
93
|
initEncryptionKey(storeDir);
|
|
@@ -492,10 +504,13 @@ export default function register(api) {
|
|
|
492
504
|
api.registerGatewayMethod("identity.session.get", createSessionGetHandler(sessionMethodDeps));
|
|
493
505
|
logInfo(api.logger, "gateway methods: identity.session.put, identity.session.get (webchat session exchange)");
|
|
494
506
|
}
|
|
495
|
-
// Preflight:
|
|
496
|
-
//
|
|
507
|
+
// Preflight: deferred to gateway_start hook so all subsystems (gateway,
|
|
508
|
+
// plugins, channels, …) have finished their synchronous plugin loading.
|
|
509
|
+
// Running inside register() would race against the next subsystem's sync
|
|
510
|
+
// load, whose event-loop blocking delays our fetch response callbacks and
|
|
511
|
+
// causes false timeouts (observed: ListUserPools 6836 ms → 55 ms once warm).
|
|
497
512
|
const authzEnabled = !!(authz?.agentCheck || authz?.toolCheck || authz?.requireRiskApproval);
|
|
498
|
-
|
|
513
|
+
const preflightDeps = {
|
|
499
514
|
pluginConfig,
|
|
500
515
|
identityClient,
|
|
501
516
|
hasIdentity,
|
|
@@ -517,13 +532,18 @@ export default function register(api) {
|
|
|
517
532
|
authzEnabled,
|
|
518
533
|
namespaceName: authz?.namespaceName ?? "default",
|
|
519
534
|
logger: api.logger,
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
535
|
+
};
|
|
536
|
+
api.on("gateway_start", async () => {
|
|
537
|
+
try {
|
|
538
|
+
const result = await runPluginPreflight(preflightDeps);
|
|
539
|
+
if (!result.ok) {
|
|
540
|
+
pluginState.degraded = true;
|
|
541
|
+
pluginState.failures = result.failures;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
catch (err) {
|
|
545
|
+
logWarn(api.logger, `[identity] preflight threw unexpectedly: ${String(err)}`);
|
|
524
546
|
}
|
|
525
|
-
}).catch((err) => {
|
|
526
|
-
logWarn(api.logger, `[identity] preflight threw unexpectedly: ${String(err)}`);
|
|
527
547
|
});
|
|
528
548
|
// Local UDS server: lets other processes on the same machine retrieve
|
|
529
549
|
// TIP tokens via HTTP-over-UDS (no network exposure, 0600 socket).
|
|
@@ -551,3 +571,8 @@ export default function register(api) {
|
|
|
551
571
|
});
|
|
552
572
|
}
|
|
553
573
|
}
|
|
574
|
+
const g = globalThis;
|
|
575
|
+
if (!g[PLUGIN_REGISTER_KEY]) {
|
|
576
|
+
g[PLUGIN_REGISTER_KEY] = registerImpl;
|
|
577
|
+
}
|
|
578
|
+
export default g[PLUGIN_REGISTER_KEY];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/local-server/handlers.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/local-server/handlers.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAUrD,oEAAoE;AACpE,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACrH,CAAC;AAEF,wEAAwE;AACxE,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,iBAAiB,KAAK,cAAc,CAAC;AAE1E,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,eAAe,CAAC;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,uBAAuB,CAAC,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC9D,MAAM,EAAE;QACN,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAC7B,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAC9B,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;KAC9B,CAAC;IACF,oEAAoE;IACpE,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CACvD,CAAC;AAwBF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,eAAe,IAc1C,KAAK,eAAe,EAAE,KAAK,cAAc,KAAG,OAAO,CAAC,IAAI,CAAC,CA+IxE"}
|
|
@@ -17,6 +17,7 @@ import { getOrRefreshTIPToken } from "../services/tip-with-refresh.js";
|
|
|
17
17
|
import { getSessionWithRefresh } from "../services/session-refresh.js";
|
|
18
18
|
import { getAllTIPTokens } from "../store/tip-store.js";
|
|
19
19
|
import { isPersonalSessionModeEnabled, PERSONAL_SESSION_STORAGE_KEY, } from "../store/sender-session-store.js";
|
|
20
|
+
import { pluginState } from "../preflight/plugin-state.js";
|
|
20
21
|
const MAIN_SESSION_KEY = "agent:main:main";
|
|
21
22
|
function resolveMainSessionKey() {
|
|
22
23
|
if (isPersonalSessionModeEnabled())
|
|
@@ -129,7 +130,11 @@ export function createRequestHandler(deps) {
|
|
|
129
130
|
ttlSec: Math.max(0, Math.floor((entry.expiresAt - now) / 1000)),
|
|
130
131
|
}));
|
|
131
132
|
json(res, 200, {
|
|
132
|
-
ok:
|
|
133
|
+
ok: !pluginState.degraded,
|
|
134
|
+
degraded: pluginState.degraded,
|
|
135
|
+
failures: pluginState.failures.length > 0
|
|
136
|
+
? pluginState.failures.map((f) => ({ check: f.check, reason: f.reason }))
|
|
137
|
+
: undefined,
|
|
133
138
|
personalSessionMode: isPersonalSessionModeEnabled(),
|
|
134
139
|
mainSessionKey: resolveMainSessionKey(),
|
|
135
140
|
activeSessions: sessions.length,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"peer-check.d.ts","sourceRoot":"","sources":["../../../src/local-server/peer-check.ts"],"names":[],"mappings":"AA+CA,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B,CAAC;AAIF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAEhE;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AACxE,MAAM,MAAM,aAAa,GAAG,CAAC,EAAE,EAAE,MAAM,KAAK,eAAe,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"peer-check.d.ts","sourceRoot":"","sources":["../../../src/local-server/peer-check.ts"],"names":[],"mappings":"AA+CA,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B,CAAC;AAIF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAEhE;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AACxE,MAAM,MAAM,aAAa,GAAG,CAAC,EAAE,EAAE,MAAM,KAAK,eAAe,GAAG,IAAI,CAAC;AAmBnE;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,aAAa,GAAG,IAAI,CAEhE;AAED,6DAA6D;AAC7D,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AAoED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,QAAQ,EACd,eAAe,GAAE,SAAS,MAAM,EAAO,GACtC,OAAO,CAUT;AAID;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,eAAe,EAAE,SAAS,MAAM,EAAE,EAClC,QAAQ,EAAE,OAAO,EACjB,QAAQ,GAAE,MAAW,GACpB;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,QAAQ,CAAA;CAAE,CAiChG"}
|
|
@@ -61,5 +61,14 @@ export type PreflightDeps = {
|
|
|
61
61
|
info?: (msg: string) => void;
|
|
62
62
|
};
|
|
63
63
|
};
|
|
64
|
+
/**
|
|
65
|
+
* Run preflight checks.
|
|
66
|
+
*
|
|
67
|
+
* Expected to be called from the `gateway_start` hook, which fires after
|
|
68
|
+
* ALL subsystems (gateway, plugins, channels, …) have finished their
|
|
69
|
+
* synchronous plugin loading and the server is listening. This guarantees
|
|
70
|
+
* the event loop is free and network requests complete promptly — no yield
|
|
71
|
+
* loops or retry hacks needed.
|
|
72
|
+
*/
|
|
64
73
|
export declare function runPluginPreflight(deps: PreflightDeps): Promise<PreflightResult>;
|
|
65
74
|
//# sourceMappingURL=plugin-preflight.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-preflight.d.ts","sourceRoot":"","sources":["../../../src/preflight/plugin-preflight.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAG9E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAO9E,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B,CAAC;AAEF;;GAEG;AACH,wBAAgB,4CAA4C,CAC1D,GAAG,EAAE,YAAY,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA0BxC;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,qFAAqF;IACrF,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,+CAA+C;IAC/C,cAAc,EAAE,uBAAuB,CAAC;IACxC,8DAA8D;IAC9D,WAAW,EAAE,OAAO,CAAC;IACrB,uDAAuD;IACvD,gBAAgB,CAAC,EAAE;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,sBAAsB,CAAC,EAAE,MAAM,CAAC;QAChC,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,0CAA0C;IAC1C,QAAQ,CAAC,EAAE;QACT,IAAI,EAAE,SAAS,GAAG,UAAU,CAAC;QAC7B,mBAAmB;QACnB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,oBAAoB;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,0DAA0D;IAC1D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,8CAA8C;IAC9C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;CACzE,CAAC;AA4JF,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"plugin-preflight.d.ts","sourceRoot":"","sources":["../../../src/preflight/plugin-preflight.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAG9E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAO9E,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B,CAAC;AAEF;;GAEG;AACH,wBAAgB,4CAA4C,CAC1D,GAAG,EAAE,YAAY,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA0BxC;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,qFAAqF;IACrF,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,+CAA+C;IAC/C,cAAc,EAAE,uBAAuB,CAAC;IACxC,8DAA8D;IAC9D,WAAW,EAAE,OAAO,CAAC;IACrB,uDAAuD;IACvD,gBAAgB,CAAC,EAAE;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,sBAAsB,CAAC,EAAE,MAAM,CAAC;QAChC,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,0CAA0C;IAC1C,QAAQ,CAAC,EAAE;QACT,IAAI,EAAE,SAAS,GAAG,UAAU,CAAC;QAC7B,mBAAmB;QACnB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,oBAAoB;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,0DAA0D;IAC1D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,8CAA8C;IAC9C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;CACzE,CAAC;AA4JF;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,eAAe,CAAC,CAwEtF"}
|
|
@@ -192,11 +192,18 @@ async function checkNamespace(deps) {
|
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
// ─── Main entry ───────────────────────────────────────────────────────────────
|
|
195
|
+
/**
|
|
196
|
+
* Run preflight checks.
|
|
197
|
+
*
|
|
198
|
+
* Expected to be called from the `gateway_start` hook, which fires after
|
|
199
|
+
* ALL subsystems (gateway, plugins, channels, …) have finished their
|
|
200
|
+
* synchronous plugin loading and the server is listening. This guarantees
|
|
201
|
+
* the event loop is free and network requests complete promptly — no yield
|
|
202
|
+
* loops or retry hacks needed.
|
|
203
|
+
*/
|
|
195
204
|
export async function runPluginPreflight(deps) {
|
|
196
205
|
const logger = deps.logger;
|
|
197
|
-
|
|
198
|
-
logger?.warn?.(`[identity] preflight failed (${failures.length} issue(s)): ${failures.map((f) => `${f.check}: ${f.reason}`).join(" | ")}`);
|
|
199
|
-
};
|
|
206
|
+
// Quick config sanity check.
|
|
200
207
|
if (deps.pluginConfig) {
|
|
201
208
|
const hit = findFirstUnrenderedPlaceholderInPluginConfig(deps.pluginConfig);
|
|
202
209
|
if (hit) {
|
|
@@ -206,7 +213,7 @@ export async function runPluginPreflight(deps) {
|
|
|
206
213
|
reason: `Configuration contains an unrendered environment variable placeholder ${hit.match} at ${hit.path}`,
|
|
207
214
|
},
|
|
208
215
|
];
|
|
209
|
-
|
|
216
|
+
logger?.warn?.(`[identity] preflight failed (${failures.length} issue(s)): ${failures.map((f) => `${f.check}: ${f.reason}`).join(" | ")}`);
|
|
210
217
|
return { ok: false, failures };
|
|
211
218
|
}
|
|
212
219
|
}
|
|
@@ -215,21 +222,19 @@ export async function runPluginPreflight(deps) {
|
|
|
215
222
|
{ name: "userpool", run: () => checkUserpool(deps) },
|
|
216
223
|
{ name: "namespace", run: () => checkNamespace(deps) },
|
|
217
224
|
];
|
|
218
|
-
|
|
225
|
+
const result = await new Promise((resolve) => {
|
|
219
226
|
let pending = steps.length;
|
|
220
227
|
let settled = false;
|
|
221
228
|
const finishOk = () => {
|
|
222
229
|
if (settled)
|
|
223
230
|
return;
|
|
224
231
|
settled = true;
|
|
225
|
-
logger?.info?.("[identity] preflight passed");
|
|
226
232
|
resolve({ ok: true, failures: [] });
|
|
227
233
|
};
|
|
228
234
|
const finishFail = (failures) => {
|
|
229
235
|
if (settled)
|
|
230
236
|
return;
|
|
231
237
|
settled = true;
|
|
232
|
-
warnFailed(failures);
|
|
233
238
|
resolve({ ok: false, failures });
|
|
234
239
|
};
|
|
235
240
|
for (const { name, run } of steps) {
|
|
@@ -246,8 +251,17 @@ export async function runPluginPreflight(deps) {
|
|
|
246
251
|
finishOk();
|
|
247
252
|
})
|
|
248
253
|
.catch((err) => {
|
|
249
|
-
finishFail([
|
|
254
|
+
finishFail([
|
|
255
|
+
{ check: name, reason: `Unexpected preflight error: ${errMsg(err)}` },
|
|
256
|
+
]);
|
|
250
257
|
});
|
|
251
258
|
}
|
|
252
259
|
});
|
|
260
|
+
if (result.ok) {
|
|
261
|
+
logger?.info?.("[identity] preflight passed");
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
logger?.warn?.(`[identity] preflight failed (${result.failures.length} issue(s)): ${result.failures.map((f) => `${f.check}: ${f.reason}`).join(" | ")}`);
|
|
265
|
+
}
|
|
266
|
+
return result;
|
|
253
267
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-state.d.ts","sourceRoot":"","sources":["../../../src/preflight/plugin-state.ts"],"names":[],"mappings":"AAgBA;;;;GAIG;AAEH,MAAM,MAAM,kBAAkB,GAC1B,eAAe,GACf,aAAa,GACb,UAAU,GACV,WAAW,CAAC;AAEhB,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,kBAAkB,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,yEAAyE;IACzE,QAAQ,EAAE,OAAO,CAAC;IAClB,iEAAiE;IACjE,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B,CAAC;
|
|
1
|
+
{"version":3,"file":"plugin-state.d.ts","sourceRoot":"","sources":["../../../src/preflight/plugin-state.ts"],"names":[],"mappings":"AAgBA;;;;GAIG;AAEH,MAAM,MAAM,kBAAkB,GAC1B,eAAe,GACf,aAAa,GACb,UAAU,GACV,WAAW,CAAC;AAEhB,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,kBAAkB,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,yEAAyE;IACzE,QAAQ,EAAE,OAAO,CAAC;IAClB,iEAAiE;IACjE,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B,CAAC;AAWF,eAAO,MAAM,WAAW,EAA2B,WAAW,CAAC"}
|
|
@@ -13,7 +13,13 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
// Share across jiti module duplicates. Two subsystems each run preflight
|
|
17
|
+
// independently — the first may time out (sets degraded=true) while the
|
|
18
|
+
// second succeeds. Without sharing, hooks from the first instance stay
|
|
19
|
+
// degraded even though the process-wide state is healthy.
|
|
20
|
+
const PLUGIN_STATE_KEY = Symbol.for("openclaw-identity.pluginState");
|
|
21
|
+
const _g = globalThis;
|
|
22
|
+
if (!_g[PLUGIN_STATE_KEY]) {
|
|
23
|
+
_g[PLUGIN_STATE_KEY] = { degraded: false, failures: [] };
|
|
24
|
+
}
|
|
25
|
+
export const pluginState = _g[PLUGIN_STATE_KEY];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity-credentials.d.ts","sourceRoot":"","sources":["../../../src/services/identity-credentials.ts"],"names":[],"mappings":"AAgCA,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AASF,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kHAAkH;IAClH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;CACrC,CAAC;
|
|
1
|
+
{"version":3,"file":"identity-credentials.d.ts","sourceRoot":"","sources":["../../../src/services/identity-credentials.ts"],"names":[],"mappings":"AAgCA,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AASF,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kHAAkH;IAClH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;CACrC,CAAC;AA8DF;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,GAAE,sBAA2B,GAChC,OAAO,CAAC,mBAAmB,CAAC,CAgE9B"}
|
|
@@ -38,17 +38,14 @@ const REMOTE_METADATA_REFRESH_BUFFER_SEC = 300;
|
|
|
38
38
|
* Returns the raw AK/SK/Token from the response, or null on failure.
|
|
39
39
|
*/
|
|
40
40
|
async function fetchRemoteMetadata(fullUrl) {
|
|
41
|
-
stsDebugLog("metadata fetch", { url: fullUrl });
|
|
42
41
|
let res;
|
|
43
42
|
try {
|
|
44
43
|
res = await fetch(fullUrl);
|
|
45
44
|
}
|
|
46
|
-
catch
|
|
47
|
-
stsDebugLog("metadata fetch failed", { error: String(err) });
|
|
45
|
+
catch {
|
|
48
46
|
return null;
|
|
49
47
|
}
|
|
50
48
|
const resText = await res.text();
|
|
51
|
-
stsDebugLog("metadata response", { status: res.status, body: resText });
|
|
52
49
|
if (!res.ok)
|
|
53
50
|
return null;
|
|
54
51
|
let json;
|
|
@@ -77,7 +74,6 @@ async function fetchRemoteMetadataThenAssumeRole(fullUrl, roleTrn) {
|
|
|
77
74
|
const creds = await fetchRemoteMetadata(fullUrl);
|
|
78
75
|
if (!creds)
|
|
79
76
|
return null;
|
|
80
|
-
stsDebugLog("metadata creds ok, calling AssumeRole", { roleTrn });
|
|
81
77
|
return assumeRole({
|
|
82
78
|
accessKeyId: creds.accessKeyId,
|
|
83
79
|
secretAccessKey: creds.secretAccessKey,
|
|
@@ -169,13 +165,6 @@ async function loadCredentialsFromFile(path) {
|
|
|
169
165
|
};
|
|
170
166
|
}
|
|
171
167
|
const STS_ENDPOINT = "https://sts.volcengineapi.com";
|
|
172
|
-
const STS_DEBUG = process.env["IDENTITY_STS_DEBUG"] === "1" || process.env["IDENTITY_STS_DEBUG"] === "true";
|
|
173
|
-
function stsDebugLog(msg, data) {
|
|
174
|
-
if (STS_DEBUG) {
|
|
175
|
-
const payload = data !== undefined ? ` ${JSON.stringify(data)}` : "";
|
|
176
|
-
console.warn(`[identity-credentials] STS AssumeRole: ${msg}${payload}`);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
168
|
/**
|
|
180
169
|
* Call STS AssumeRole to get temporary credentials.
|
|
181
170
|
* Uses GET with params in query per volcengine-nodejs-sdk (metaPath: get/text_plain).
|
|
@@ -221,22 +210,11 @@ async function assumeRole(params) {
|
|
|
221
210
|
Accept: "application/json",
|
|
222
211
|
...signedHeaders,
|
|
223
212
|
};
|
|
224
|
-
stsDebugLog("request", {
|
|
225
|
-
method: "GET",
|
|
226
|
-
url: url.toString(),
|
|
227
|
-
query,
|
|
228
|
-
headers: { ...headers, Authorization: "(redacted)" },
|
|
229
|
-
});
|
|
230
213
|
const res = await fetch(url.toString(), {
|
|
231
214
|
method: "GET",
|
|
232
215
|
headers,
|
|
233
216
|
});
|
|
234
217
|
const resText = await res.text();
|
|
235
|
-
stsDebugLog("response", {
|
|
236
|
-
status: res.status,
|
|
237
|
-
statusText: res.statusText,
|
|
238
|
-
body: resText,
|
|
239
|
-
});
|
|
240
218
|
if (!res.ok) {
|
|
241
219
|
throw new Error(`STS AssumeRole failed ${res.status}: ${resText}`);
|
|
242
220
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../../../src/store/encryption.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../../../src/store/encryption.ts"],"names":[],"mappings":"AA2EA;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAMxD;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,CAIxD;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAS9D;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAaxD;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOxB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAGf;AAID,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAGnE;AAED,kEAAkE;AAClE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAM/D;AAED,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAExD;AAED,4DAA4D;AAC5D,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC"}
|
|
@@ -33,8 +33,12 @@ const SALT_LEN = 32;
|
|
|
33
33
|
const SALT_FILENAME = ".key-salt";
|
|
34
34
|
const PEPPER = "openclaw-identity-plugin-v1-AES256GCM-7f3a9c";
|
|
35
35
|
const HKDF_INFO = "openclaw-identity-enc";
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
const ENC_STATE_KEY = Symbol.for("openclaw-identity.encryptionState");
|
|
37
|
+
const _g = globalThis;
|
|
38
|
+
if (!_g[ENC_STATE_KEY]) {
|
|
39
|
+
_g[ENC_STATE_KEY] = { cachedKey: null, initPromise: null };
|
|
40
|
+
}
|
|
41
|
+
const encState = _g[ENC_STATE_KEY];
|
|
38
42
|
async function readOrCreateSalt(storeDir) {
|
|
39
43
|
const saltPath = path.join(storeDir, SALT_FILENAME);
|
|
40
44
|
try {
|
|
@@ -60,10 +64,10 @@ async function deriveKey(storeDir) {
|
|
|
60
64
|
* is fine — the returned promise is awaited lazily by getEncryptionKey).
|
|
61
65
|
*/
|
|
62
66
|
export function initEncryptionKey(storeDir) {
|
|
63
|
-
if (cachedKey || initPromise)
|
|
67
|
+
if (encState.cachedKey || encState.initPromise)
|
|
64
68
|
return;
|
|
65
|
-
initPromise = deriveKey(storeDir).then((key) => {
|
|
66
|
-
cachedKey = key;
|
|
69
|
+
encState.initPromise = deriveKey(storeDir).then((key) => {
|
|
70
|
+
encState.cachedKey = key;
|
|
67
71
|
return key;
|
|
68
72
|
});
|
|
69
73
|
}
|
|
@@ -72,10 +76,10 @@ export function initEncryptionKey(storeDir) {
|
|
|
72
76
|
* completed yet. Callers in async hooks simply `await getEncryptionKey()`.
|
|
73
77
|
*/
|
|
74
78
|
export async function getEncryptionKey() {
|
|
75
|
-
if (cachedKey)
|
|
76
|
-
return cachedKey;
|
|
77
|
-
if (initPromise)
|
|
78
|
-
return initPromise;
|
|
79
|
+
if (encState.cachedKey)
|
|
80
|
+
return encState.cachedKey;
|
|
81
|
+
if (encState.initPromise)
|
|
82
|
+
return encState.initPromise;
|
|
79
83
|
throw new Error("Encryption key not initialized — call initEncryptionKey first");
|
|
80
84
|
}
|
|
81
85
|
export function encrypt(key, plaintext) {
|
|
@@ -142,6 +146,6 @@ export function isEncryptedField(value) {
|
|
|
142
146
|
}
|
|
143
147
|
/** Reset cached key and init promise (for testing only). */
|
|
144
148
|
export function __resetCachedKey() {
|
|
145
|
-
cachedKey = null;
|
|
146
|
-
initPromise = null;
|
|
149
|
+
encState.cachedKey = null;
|
|
150
|
+
encState.initPromise = null;
|
|
147
151
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@m1a0rz/agent-identity",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Agent Identity: UserPool (用户池) login, TIP token (工作负载令牌), credential hosting (凭据托管 OAuth2/API key), optional tool/skill permission control (CheckPermission) and risk approval. Integrates with Volcengine 智能体身份和权限管理平台.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -51,7 +51,15 @@
|
|
|
51
51
|
"openclaw": {
|
|
52
52
|
"extensions": [
|
|
53
53
|
"./dist/index.js"
|
|
54
|
-
]
|
|
54
|
+
],
|
|
55
|
+
"compat": {
|
|
56
|
+
"pluginApi": ">=2026.3.24",
|
|
57
|
+
"minGatewayVersion": "2026.3.24"
|
|
58
|
+
},
|
|
59
|
+
"build": {
|
|
60
|
+
"openclawVersion": "2026.3.28",
|
|
61
|
+
"pluginSdkVersion": "2026.3.28"
|
|
62
|
+
}
|
|
55
63
|
},
|
|
56
64
|
"files": [
|
|
57
65
|
"dist",
|