@ory/argus 0.13.7 → 0.13.9
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/adapters.d.ts +16 -0
- package/dist/adapters.js +78 -27
- package/dist/build-info.json +4 -4
- package/dist/client.d.ts +31 -0
- package/dist/client.js +58 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +7 -4
- package/dist/interactive-setup.js +6 -1
- package/dist/logger.d.ts +21 -0
- package/dist/logger.js +38 -2
- package/dist/permissions-cli.js +18 -5
- package/dist/status-cli.js +31 -23
- package/dist/testing.d.ts +8 -0
- package/dist/testing.js +20 -1
- package/package.json +1 -1
package/dist/adapters.d.ts
CHANGED
|
@@ -43,6 +43,14 @@ export interface SessionStartOptions {
|
|
|
43
43
|
* user gate still runs, refreshes tokens, and records the `user.auth` span.
|
|
44
44
|
*/
|
|
45
45
|
export declare function sessionStart(client: OryAgentClient, opts: SessionStartOptions): Promise<SessionStartResult>;
|
|
46
|
+
/**
|
|
47
|
+
* Write the `user → agent` delegation tuple, at most once per install
|
|
48
|
+
* (see {@link writeDelegationOnce}). Exported so harness plugins that run
|
|
49
|
+
* their own session-start sequence (rather than {@link sessionStart}) share
|
|
50
|
+
* the same write-once semantics instead of re-issuing the write every
|
|
51
|
+
* session. No-op until both principals are populated.
|
|
52
|
+
*/
|
|
53
|
+
export declare function writeUserDelegatesAgent(client: OryAgentClient): Promise<void>;
|
|
46
54
|
export interface RegisterSubagentOptions {
|
|
47
55
|
harness: string;
|
|
48
56
|
subAgentType: string;
|
|
@@ -50,6 +58,14 @@ export interface RegisterSubagentOptions {
|
|
|
50
58
|
subAgentGate?: typeof ensureSubAgentIdentity;
|
|
51
59
|
}
|
|
52
60
|
export declare function registerSubagent(client: OryAgentClient, opts: RegisterSubagentOptions): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Write the `agent → subagent` delegation tuple, at most once per install
|
|
63
|
+
* (see {@link writeDelegationOnce}). Exported so harness plugins that
|
|
64
|
+
* resolve the sub-agent identity through their own event plumbing (rather
|
|
65
|
+
* than {@link registerSubagent}) still share the write-once semantics.
|
|
66
|
+
* No-op until the agent principal is populated.
|
|
67
|
+
*/
|
|
68
|
+
export declare function writeAgentDelegatesSubagent(client: OryAgentClient, subAgentSubject: string, subAgentType: string): Promise<void>;
|
|
53
69
|
export interface GateResult {
|
|
54
70
|
/** False only when the tool was hard-denied in enforce mode. */
|
|
55
71
|
proceed: boolean;
|
package/dist/adapters.js
CHANGED
|
@@ -21,7 +21,9 @@
|
|
|
21
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
22
|
exports.resolveNamespace = resolveNamespace;
|
|
23
23
|
exports.sessionStart = sessionStart;
|
|
24
|
+
exports.writeUserDelegatesAgent = writeUserDelegatesAgent;
|
|
24
25
|
exports.registerSubagent = registerSubagent;
|
|
26
|
+
exports.writeAgentDelegatesSubagent = writeAgentDelegatesSubagent;
|
|
25
27
|
exports.gate = gate;
|
|
26
28
|
exports.complete = complete;
|
|
27
29
|
exports.wrapTool = wrapTool;
|
|
@@ -52,7 +54,7 @@ async function sessionStart(client, opts) {
|
|
|
52
54
|
projectUrl,
|
|
53
55
|
harness: opts.harness,
|
|
54
56
|
});
|
|
55
|
-
await
|
|
57
|
+
await writeUserDelegatesAgent(client);
|
|
56
58
|
return {
|
|
57
59
|
proceed: decision.proceed,
|
|
58
60
|
userMode: decision.mode,
|
|
@@ -60,25 +62,63 @@ async function sessionStart(client, opts) {
|
|
|
60
62
|
agentKind: creds.kind,
|
|
61
63
|
};
|
|
62
64
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
/**
|
|
66
|
+
* Write a delegation tuple at most once. The tuple is stable for a given
|
|
67
|
+
* (namespace, object, subject), and Keto's create API is not idempotent, so
|
|
68
|
+
* this goes through {@link OryAgentClient.ensureRelationship}: it reads the
|
|
69
|
+
* exact tuple first and only writes when absent — no duplicate on repeated
|
|
70
|
+
* session starts, and self-healing if the tuple was deleted. If the existence
|
|
71
|
+
* probe fails we skip the write rather than risk a duplicate (delegation
|
|
72
|
+
* tuples are audit-only, so a missed write is harmless and retried next
|
|
73
|
+
* session). Best-effort: any failure is logged and swallowed.
|
|
74
|
+
*/
|
|
75
|
+
async function writeDelegationOnce(client, check, options) {
|
|
68
76
|
try {
|
|
69
|
-
await client.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
const res = await client.ensureRelationship(check, {
|
|
78
|
+
spanAttributes: options.spanAttributes,
|
|
79
|
+
});
|
|
80
|
+
if (res.probeError) {
|
|
81
|
+
client.logger.debug("delegation.probe_failed", {
|
|
82
|
+
...options.failedContext,
|
|
83
|
+
message: res.probeError.message,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
75
86
|
}
|
|
76
87
|
catch (err) {
|
|
77
|
-
client.logger.warn(
|
|
88
|
+
client.logger.warn(options.failedEvent, {
|
|
89
|
+
...options.failedContext,
|
|
78
90
|
message: err instanceof Error ? err.message : String(err),
|
|
79
91
|
});
|
|
80
92
|
}
|
|
81
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Write the `user → agent` delegation tuple, at most once per install
|
|
96
|
+
* (see {@link writeDelegationOnce}). Exported so harness plugins that run
|
|
97
|
+
* their own session-start sequence (rather than {@link sessionStart}) share
|
|
98
|
+
* the same write-once semantics instead of re-issuing the write every
|
|
99
|
+
* session. No-op until both principals are populated.
|
|
100
|
+
*/
|
|
101
|
+
async function writeUserDelegatesAgent(client) {
|
|
102
|
+
const user = client.userPrincipal.subject;
|
|
103
|
+
const agent = client.agentPrincipal.subject;
|
|
104
|
+
if (!user || !agent) {
|
|
105
|
+
client.logger.debug("delegation.skip", {
|
|
106
|
+
reason: "missing principal",
|
|
107
|
+
hasUser: !!user,
|
|
108
|
+
hasAgent: !!agent,
|
|
109
|
+
});
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
await writeDelegationOnce(client, {
|
|
113
|
+
namespace: resolveNamespace(),
|
|
114
|
+
object: `agent:${agent}`,
|
|
115
|
+
relation: "delegate",
|
|
116
|
+
subjectId: `user:${user}`,
|
|
117
|
+
}, {
|
|
118
|
+
spanAttributes: { delegation: "user-to-agent" },
|
|
119
|
+
failedEvent: "delegation.user_to_agent.failed",
|
|
120
|
+
});
|
|
121
|
+
}
|
|
82
122
|
async function registerSubagent(client, opts) {
|
|
83
123
|
const projectUrl = opts.projectUrl ?? (0, config_js_1.resolveConfig)().projectUrl;
|
|
84
124
|
const subAgentGate = opts.subAgentGate ?? agent_auth_js_1.ensureSubAgentIdentity;
|
|
@@ -99,23 +139,34 @@ async function registerSubagent(client, opts) {
|
|
|
99
139
|
}
|
|
100
140
|
if (identity.kind !== "dynamic" || !identity.subject)
|
|
101
141
|
return;
|
|
142
|
+
await writeAgentDelegatesSubagent(client, identity.subject, opts.subAgentType);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Write the `agent → subagent` delegation tuple, at most once per install
|
|
146
|
+
* (see {@link writeDelegationOnce}). Exported so harness plugins that
|
|
147
|
+
* resolve the sub-agent identity through their own event plumbing (rather
|
|
148
|
+
* than {@link registerSubagent}) still share the write-once semantics.
|
|
149
|
+
* No-op until the agent principal is populated.
|
|
150
|
+
*/
|
|
151
|
+
async function writeAgentDelegatesSubagent(client, subAgentSubject, subAgentType) {
|
|
102
152
|
const agent = client.agentPrincipal.subject;
|
|
103
|
-
if (!agent)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
namespace: resolveNamespace(),
|
|
108
|
-
object: `subagent:${identity.subject}`,
|
|
109
|
-
relation: "delegate",
|
|
110
|
-
subjectId: `agent:${agent}`,
|
|
111
|
-
}, { spanAttributes: { delegation: "agent-to-subagent", subAgentType: opts.subAgentType } });
|
|
112
|
-
}
|
|
113
|
-
catch (err) {
|
|
114
|
-
client.logger.warn("delegation.agent_to_subagent.failed", {
|
|
115
|
-
subAgentType: opts.subAgentType,
|
|
116
|
-
message: err instanceof Error ? err.message : String(err),
|
|
153
|
+
if (!agent) {
|
|
154
|
+
client.logger.debug("delegation.skip", {
|
|
155
|
+
reason: "agent principal not populated",
|
|
156
|
+
subAgentType,
|
|
117
157
|
});
|
|
158
|
+
return;
|
|
118
159
|
}
|
|
160
|
+
await writeDelegationOnce(client, {
|
|
161
|
+
namespace: resolveNamespace(),
|
|
162
|
+
object: `subagent:${subAgentSubject}`,
|
|
163
|
+
relation: "delegate",
|
|
164
|
+
subjectId: `agent:${agent}`,
|
|
165
|
+
}, {
|
|
166
|
+
spanAttributes: { delegation: "agent-to-subagent", subAgentType },
|
|
167
|
+
failedEvent: "delegation.agent_to_subagent.failed",
|
|
168
|
+
failedContext: { subAgentType },
|
|
169
|
+
});
|
|
119
170
|
}
|
|
120
171
|
/**
|
|
121
172
|
* Authorize a tool call, record the spans, and return a normalized {@link GateResult}.
|
package/dist/build-info.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"repo": "ory-agent-plugins",
|
|
3
|
-
"commit": "
|
|
4
|
-
"commitShort": "
|
|
3
|
+
"commit": "f7663bf2a792378be5a94c7d6bb0d6671e1da6a9",
|
|
4
|
+
"commitShort": "f7663bf",
|
|
5
5
|
"branch": "main",
|
|
6
|
-
"commitDate": "2026-07-
|
|
6
|
+
"commitDate": "2026-07-15T15:56:35-07:00",
|
|
7
7
|
"dirty": false,
|
|
8
|
-
"builtAt": "2026-07-
|
|
8
|
+
"builtAt": "2026-07-15T23:00:39.070Z"
|
|
9
9
|
}
|
package/dist/client.d.ts
CHANGED
|
@@ -159,6 +159,37 @@ export declare class OryAgentClient {
|
|
|
159
159
|
created: boolean;
|
|
160
160
|
alreadyExisted: boolean;
|
|
161
161
|
}>;
|
|
162
|
+
/**
|
|
163
|
+
* True if the *exact* relation tuple already exists in Keto. Queries the
|
|
164
|
+
* relation-tuple listing API filtered by the tuple's own coordinates
|
|
165
|
+
* (namespace/object/relation + subject), so — unlike `checkPermission` —
|
|
166
|
+
* it does not follow subject-set expansion: it answers "is this literal
|
|
167
|
+
* tuple stored?", not "does this permission resolve?". Throws a classified
|
|
168
|
+
* {@link OryError} if the query itself fails.
|
|
169
|
+
*/
|
|
170
|
+
relationshipExists(check: PermissionCheck): Promise<boolean>;
|
|
171
|
+
/**
|
|
172
|
+
* Idempotent relationship write. Keto's create API is **not** idempotent —
|
|
173
|
+
* `PUT /admin/relation-tuples` inserts a fresh row on every call (each with
|
|
174
|
+
* a new primary key) and never returns 409, so calling `createRelationship`
|
|
175
|
+
* on repeated bootstraps / session starts accumulates duplicate tuples.
|
|
176
|
+
* This reads the exact tuple first (via {@link relationshipExists}) and only
|
|
177
|
+
* writes when it is absent — which also self-heals if the tuple was deleted
|
|
178
|
+
* out of band.
|
|
179
|
+
*
|
|
180
|
+
* If the existence probe itself fails, the tuple is left untouched (we do
|
|
181
|
+
* not write blind, to avoid re-introducing duplicates when the read path is
|
|
182
|
+
* misbehaving) and the classified error is returned as `probeError`. Callers
|
|
183
|
+
* that must guarantee the grant exists (e.g. install-time bootstrap) can
|
|
184
|
+
* fall back to {@link createRelationship} when `probeError` is set.
|
|
185
|
+
*/
|
|
186
|
+
ensureRelationship(check: PermissionCheck, options?: {
|
|
187
|
+
spanAttributes?: Record<string, unknown>;
|
|
188
|
+
}): Promise<{
|
|
189
|
+
created: boolean;
|
|
190
|
+
alreadyExisted: boolean;
|
|
191
|
+
probeError?: OryError;
|
|
192
|
+
}>;
|
|
162
193
|
/**
|
|
163
194
|
* Delete a relation tuple in Keto. Missing tuples (404) are treated as
|
|
164
195
|
* success so callers can call this idempotently when unwinding state.
|
package/dist/client.js
CHANGED
|
@@ -551,6 +551,64 @@ class OryAgentClient {
|
|
|
551
551
|
throw oryErr;
|
|
552
552
|
}
|
|
553
553
|
}
|
|
554
|
+
/**
|
|
555
|
+
* True if the *exact* relation tuple already exists in Keto. Queries the
|
|
556
|
+
* relation-tuple listing API filtered by the tuple's own coordinates
|
|
557
|
+
* (namespace/object/relation + subject), so — unlike `checkPermission` —
|
|
558
|
+
* it does not follow subject-set expansion: it answers "is this literal
|
|
559
|
+
* tuple stored?", not "does this permission resolve?". Throws a classified
|
|
560
|
+
* {@link OryError} if the query itself fails.
|
|
561
|
+
*/
|
|
562
|
+
async relationshipExists(check) {
|
|
563
|
+
try {
|
|
564
|
+
const response = await this.relationship.getRelationships({
|
|
565
|
+
namespace: check.namespace,
|
|
566
|
+
object: check.object,
|
|
567
|
+
relation: check.relation,
|
|
568
|
+
...(check.subjectId ? { subjectId: check.subjectId } : {}),
|
|
569
|
+
...(check.subjectSet
|
|
570
|
+
? {
|
|
571
|
+
subjectSetNamespace: check.subjectSet.namespace,
|
|
572
|
+
subjectSetObject: check.subjectSet.object,
|
|
573
|
+
subjectSetRelation: check.subjectSet.relation,
|
|
574
|
+
}
|
|
575
|
+
: {}),
|
|
576
|
+
pageSize: 1,
|
|
577
|
+
});
|
|
578
|
+
const tuples = response.data?.relation_tuples ?? [];
|
|
579
|
+
return tuples.length > 0;
|
|
580
|
+
}
|
|
581
|
+
catch (err) {
|
|
582
|
+
throw this.classifyError(err);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Idempotent relationship write. Keto's create API is **not** idempotent —
|
|
587
|
+
* `PUT /admin/relation-tuples` inserts a fresh row on every call (each with
|
|
588
|
+
* a new primary key) and never returns 409, so calling `createRelationship`
|
|
589
|
+
* on repeated bootstraps / session starts accumulates duplicate tuples.
|
|
590
|
+
* This reads the exact tuple first (via {@link relationshipExists}) and only
|
|
591
|
+
* writes when it is absent — which also self-heals if the tuple was deleted
|
|
592
|
+
* out of band.
|
|
593
|
+
*
|
|
594
|
+
* If the existence probe itself fails, the tuple is left untouched (we do
|
|
595
|
+
* not write blind, to avoid re-introducing duplicates when the read path is
|
|
596
|
+
* misbehaving) and the classified error is returned as `probeError`. Callers
|
|
597
|
+
* that must guarantee the grant exists (e.g. install-time bootstrap) can
|
|
598
|
+
* fall back to {@link createRelationship} when `probeError` is set.
|
|
599
|
+
*/
|
|
600
|
+
async ensureRelationship(check, options) {
|
|
601
|
+
let exists;
|
|
602
|
+
try {
|
|
603
|
+
exists = await this.relationshipExists(check);
|
|
604
|
+
}
|
|
605
|
+
catch (err) {
|
|
606
|
+
return { created: false, alreadyExisted: false, probeError: err };
|
|
607
|
+
}
|
|
608
|
+
if (exists)
|
|
609
|
+
return { created: false, alreadyExisted: true };
|
|
610
|
+
return this.createRelationship(check, options);
|
|
611
|
+
}
|
|
554
612
|
/**
|
|
555
613
|
* Delete a relation tuple in Keto. Missing tuples (404) are treated as
|
|
556
614
|
* success so callers can call this idempotently when unwinding state.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { OryAgentClient, type OryAgentConfig, type PrincipalIdentity, } from "./client.js";
|
|
2
|
-
export { DebugLogger, redactLogData, type LogEntry, type LogLevel, } from "./logger.js";
|
|
2
|
+
export { DebugLogger, redactLogData, withQuietStderr, type LogEntry, type LogLevel, } from "./logger.js";
|
|
3
3
|
export { Tracer, ActiveSpan, deriveTraceId, formatSpan, watchTraceFile, type TraceEvent, type SpanStatus, type TraceSpan, type SpanOptions, type TracerOptions, type TracerContext, type SpanAttributeEnricher, } from "./tracer.js";
|
|
4
4
|
export { loadConfig, saveConfig, resolveConfig, mutateConfig, getConfigPath, getDataDir, getHarnessDataDir, type OryPluginConfig, type OryOAuth2Tokens, type OryUserCredentials, type OryAgentCredentialsBlock, type OryAgentDynamicCredentials, type PermissionMode, } from "./config.js";
|
|
5
5
|
export { pkceLogin, refreshAccessToken, detectHeadless, generateCodeVerifier, sha256Base64Url, buildAuthorizeUrl, LOOPBACK_PORTS, DEFAULT_LOGIN_TIMEOUT_MS, type PkceLoginOptions, type PkceLoginOutcome, type PkceDeclineReason, } from "./auth.js";
|
|
@@ -27,4 +27,4 @@ export { resolveUserSubject, runWithUserSubject, subjectLabel, type UserSubjectR
|
|
|
27
27
|
export { formatDenialMessage, formatDenialSummary, formatAlertMessage, formatAlertSummary, alertAttributes, OryDenialError, type DenialContext, type AlertAttributes, } from "./denial.js";
|
|
28
28
|
export { summarizeToolInput, summarizeToolOutput, type ToolInputSummary, type ToolOutputSummary, } from "./tool-metadata.js";
|
|
29
29
|
export { OtlpExporter, otlpExporterFromEnv, parseKeyValueList, type SpanExporter, type OtlpExporterOptions, type OtlpProtocol, } from "./otel/index.js";
|
|
30
|
-
export { resolveNamespace, sessionStart, gate, complete, registerSubagent, wrapTool, type SessionStartResult, type SessionStartOptions, type RegisterSubagentOptions, type GateResult, type GateOptions, type WrapToolOptions, } from "./adapters.js";
|
|
30
|
+
export { resolveNamespace, sessionStart, gate, complete, registerSubagent, writeUserDelegatesAgent, writeAgentDelegatesSubagent, wrapTool, type SessionStartResult, type SessionStartOptions, type RegisterSubagentOptions, type GateResult, type GateOptions, type WrapToolOptions, } from "./adapters.js";
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.
|
|
5
|
-
exports.
|
|
6
|
-
exports.wrapTool = exports.registerSubagent = exports.complete = exports.gate = exports.sessionStart = exports.resolveNamespace = exports.parseKeyValueList = void 0;
|
|
3
|
+
exports.clearCredentialsForUninstall = exports.AGENT_TOKEN_EXPIRY_SKEW_SEC = exports.revokeAgentDynamicClient = exports.clearSubAgentDynamicCredentials = exports.saveSubAgentDynamicCredentials = exports.loadSubAgentDynamicCredentials = exports.clearAgentDynamicCredentials = exports.saveAgentDynamicCredentials = exports.loadAgentDynamicCredentials = exports.registerAgentClient = exports.fetchClientCredentialsToken = exports.ensureSubAgentIdentity = exports.ensureAgentIdentity = exports.resolveAgentCredentials = exports.ensureAuthenticated = exports.ensureUserAuthenticated = exports.TOKEN_EXPIRY_SKEW_SEC = exports.waitForPeerTokensSync = exports.waitForPeerTokens = exports.clearPkceFlightLock = exports.tryAcquirePkceFlightLock = exports.refreshAndSave = exports.isExpired = exports.clearTokens = exports.saveTokens = exports.loadTokens = exports.DEFAULT_LOGIN_TIMEOUT_MS = exports.LOOPBACK_PORTS = exports.buildAuthorizeUrl = exports.sha256Base64Url = exports.generateCodeVerifier = exports.detectHeadless = exports.refreshAccessToken = exports.pkceLogin = exports.getHarnessDataDir = exports.getDataDir = exports.getConfigPath = exports.mutateConfig = exports.resolveConfig = exports.saveConfig = exports.loadConfig = exports.watchTraceFile = exports.formatSpan = exports.deriveTraceId = exports.ActiveSpan = exports.Tracer = exports.withQuietStderr = exports.redactLogData = exports.DebugLogger = exports.OryAgentClient = void 0;
|
|
4
|
+
exports.unregisterPlugin = exports.registerPlugin = exports.removeMcpServer = exports.mergeMcpServer = exports.mcpServerEntry = exports.resolveMcpServerCommand = exports.emitDeferredNextSteps = exports.beginDeferNextSteps = exports.nextStepsSink = exports.printNextSteps = exports.printSetupHelp = exports.removeFlatHooks = exports.mergeFlatHooks = exports.flatHookEntry = exports.removeMatcherHooks = exports.mergeMatcherHooks = exports.matcherHookEntry = exports.resolveHookCommand = exports.isOryHookCommand = exports.writeJsonFile = exports.readJsonFile = exports.parseSetupArgs = exports.resolveBuildInfo = exports.collectVersionInfo = exports.runVersionCommand = exports.printPermissionsSection = exports.printAgentIdentitySection = exports.printUserIdentitySection = exports.runStatusCommand = exports.LOOPBACK_REDIRECT_URIS = exports.projectUrlFromSlug = exports.runPostInstall = exports.runInteractiveSetup = exports.printPermissionsOnboardingHelp = exports.maybeAutoBootstrap = exports.isUserIdentityCached = exports.runPermissionsCommand = exports.oryNpx = exports.interactiveConfigPrompt = exports.promptForProjectUrl = exports.promptOnTty = exports.isTtyAvailable = exports.runWatchCommand = exports.printTraceTail = exports.printEnvHelp = exports.printLogTail = exports.printEnvironment = exports.printOryConfig = exports.runAgentCommand = exports.runConfigureCommand = void 0;
|
|
5
|
+
exports.OtlpExporter = exports.summarizeToolOutput = exports.summarizeToolInput = exports.OryDenialError = exports.alertAttributes = exports.formatAlertSummary = exports.formatAlertMessage = exports.formatDenialSummary = exports.formatDenialMessage = exports.subjectLabel = exports.runWithUserSubject = exports.resolveUserSubject = exports.checkMcpPermission = exports.parseMcpToolGeneric = exports.parseGeminiMcpTool = exports.parseClaudeCodeMcpTool = exports.TOOL_EXECUTION_PHASES = exports.USER_FACING_PHASES = exports.HARNESS_LIFECYCLE_MAP = exports.isToolExecutionPhase = exports.isUserFacingPhase = exports.classifyLifecycle = exports.isInteractiveTool = exports.getInteractiveToolCatalog = exports.INTERACTIVE_TOOL_CATALOG = exports.getToolCatalog = exports.ALL_TOOLS = exports.KNOWN_HARNESSES = exports.HARNESS_TOOL_CATALOG = exports.gateToolCall = exports.applyPermissionMode = exports.checkAndDecide = exports.runRegistryCommand = exports.DEV_JAEGER_CONTAINER = exports.stopDevJaeger = exports.ensureDevJaeger = exports.runLocalCommand = exports.ORY_COMMAND_SLUGS = exports.ORY_COMMAND_SKILL_NAMES = exports.ORY_SKILL_NAMES = exports.removeSkillDirs = exports.writeSkillTree = exports.toSkillMarkdown = exports.commandToPlainMarkdown = exports.commandToFrontmatterMarkdown = exports.commandToToml = exports.commandToSkill = exports.renderOryCommands = exports.renderOrySkills = exports.runDevLauncher = void 0;
|
|
6
|
+
exports.wrapTool = exports.writeAgentDelegatesSubagent = exports.writeUserDelegatesAgent = exports.registerSubagent = exports.complete = exports.gate = exports.sessionStart = exports.resolveNamespace = exports.parseKeyValueList = exports.otlpExporterFromEnv = void 0;
|
|
7
7
|
var client_js_1 = require("./client.js");
|
|
8
8
|
Object.defineProperty(exports, "OryAgentClient", { enumerable: true, get: function () { return client_js_1.OryAgentClient; } });
|
|
9
9
|
var logger_js_1 = require("./logger.js");
|
|
10
10
|
Object.defineProperty(exports, "DebugLogger", { enumerable: true, get: function () { return logger_js_1.DebugLogger; } });
|
|
11
11
|
Object.defineProperty(exports, "redactLogData", { enumerable: true, get: function () { return logger_js_1.redactLogData; } });
|
|
12
|
+
Object.defineProperty(exports, "withQuietStderr", { enumerable: true, get: function () { return logger_js_1.withQuietStderr; } });
|
|
12
13
|
var tracer_js_1 = require("./tracer.js");
|
|
13
14
|
Object.defineProperty(exports, "Tracer", { enumerable: true, get: function () { return tracer_js_1.Tracer; } });
|
|
14
15
|
Object.defineProperty(exports, "ActiveSpan", { enumerable: true, get: function () { return tracer_js_1.ActiveSpan; } });
|
|
@@ -189,4 +190,6 @@ Object.defineProperty(exports, "sessionStart", { enumerable: true, get: function
|
|
|
189
190
|
Object.defineProperty(exports, "gate", { enumerable: true, get: function () { return adapters_js_1.gate; } });
|
|
190
191
|
Object.defineProperty(exports, "complete", { enumerable: true, get: function () { return adapters_js_1.complete; } });
|
|
191
192
|
Object.defineProperty(exports, "registerSubagent", { enumerable: true, get: function () { return adapters_js_1.registerSubagent; } });
|
|
193
|
+
Object.defineProperty(exports, "writeUserDelegatesAgent", { enumerable: true, get: function () { return adapters_js_1.writeUserDelegatesAgent; } });
|
|
194
|
+
Object.defineProperty(exports, "writeAgentDelegatesSubagent", { enumerable: true, get: function () { return adapters_js_1.writeAgentDelegatesSubagent; } });
|
|
192
195
|
Object.defineProperty(exports, "wrapTool", { enumerable: true, get: function () { return adapters_js_1.wrapTool; } });
|
|
@@ -82,6 +82,7 @@ const cli_js_1 = require("./cli.js");
|
|
|
82
82
|
const cli_invocation_js_1 = require("./cli-invocation.js");
|
|
83
83
|
const auth_js_1 = require("./auth.js");
|
|
84
84
|
const client_js_1 = require("./client.js");
|
|
85
|
+
const logger_js_1 = require("./logger.js");
|
|
85
86
|
const user_login_js_1 = require("./user-login.js");
|
|
86
87
|
const agent_auth_js_1 = require("./agent-auth.js");
|
|
87
88
|
const tool_catalog_js_1 = require("./tool-catalog.js");
|
|
@@ -261,8 +262,12 @@ async function runInteractiveSetup(binName, harness, args = [], deps = {}) {
|
|
|
261
262
|
ttyPrompter = createTtyPrompter();
|
|
262
263
|
}
|
|
263
264
|
};
|
|
265
|
+
// Quiet the structured stderr firehose for the duration of the wizard so
|
|
266
|
+
// `[ory-agent] {...}` debug lines don't interleave with the human-facing UI
|
|
267
|
+
// when a session runs with ORY_AGENT_DEBUG=true (the dev launcher always
|
|
268
|
+
// sets it). Debug still lands in the log file.
|
|
264
269
|
try {
|
|
265
|
-
return await runWizard(binName, harness, { runner, prompt, deps, runInteractive });
|
|
270
|
+
return await (0, logger_js_1.withQuietStderr)(() => runWizard(binName, harness, { runner, prompt, deps, runInteractive }));
|
|
266
271
|
}
|
|
267
272
|
catch (err) {
|
|
268
273
|
const msg = err instanceof Error ? err.message : String(err);
|
package/dist/logger.d.ts
CHANGED
|
@@ -12,6 +12,15 @@ export interface LogEntry {
|
|
|
12
12
|
*/
|
|
13
13
|
export declare function redactLogData(value: unknown): unknown;
|
|
14
14
|
export declare class DebugLogger {
|
|
15
|
+
/**
|
|
16
|
+
* Process-global switch to suppress the stderr firehose while still writing
|
|
17
|
+
* to the log file. The interactive installer sets this so structured debug
|
|
18
|
+
* JSON (`[ory-agent] {...}`) doesn't interleave with the wizard's
|
|
19
|
+
* human-facing UI when a session runs with `ORY_AGENT_DEBUG=true` (the dev
|
|
20
|
+
* launcher, for one, always sets it). File logging — the real observability
|
|
21
|
+
* channel — is unaffected.
|
|
22
|
+
*/
|
|
23
|
+
static stderrSuppressed: boolean;
|
|
15
24
|
enabled: boolean;
|
|
16
25
|
harness: string;
|
|
17
26
|
logFile: string | null;
|
|
@@ -27,3 +36,15 @@ export declare class DebugLogger {
|
|
|
27
36
|
warn(event: string, data?: Record<string, unknown>): void;
|
|
28
37
|
error(event: string, data?: Record<string, unknown>): void;
|
|
29
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Run `fn` with the structured stderr firehose suppressed, restoring the
|
|
41
|
+
* previous state afterward (even on throw). File logging is unaffected.
|
|
42
|
+
*
|
|
43
|
+
* Human-facing CLI commands (the interactive installer, `status`,
|
|
44
|
+
* `permissions status`/`bootstrap`) spin up a client and emit debug/info
|
|
45
|
+
* events; when the process runs with `ORY_AGENT_DEBUG=true` (the dev launcher
|
|
46
|
+
* always sets it) those `[ory-agent] {...}` lines would interleave with the
|
|
47
|
+
* command's polished output. Wrapping the command body in this keeps the
|
|
48
|
+
* terminal clean while the log file still captures everything.
|
|
49
|
+
*/
|
|
50
|
+
export declare function withQuietStderr<T>(fn: () => Promise<T> | T): Promise<T>;
|
package/dist/logger.js
CHANGED
|
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.DebugLogger = void 0;
|
|
37
37
|
exports.redactLogData = redactLogData;
|
|
38
|
+
exports.withQuietStderr = withQuietStderr;
|
|
38
39
|
const fs = __importStar(require("node:fs"));
|
|
39
40
|
const path = __importStar(require("node:path"));
|
|
40
41
|
/**
|
|
@@ -82,6 +83,15 @@ function redactLogData(value) {
|
|
|
82
83
|
return value;
|
|
83
84
|
}
|
|
84
85
|
class DebugLogger {
|
|
86
|
+
/**
|
|
87
|
+
* Process-global switch to suppress the stderr firehose while still writing
|
|
88
|
+
* to the log file. The interactive installer sets this so structured debug
|
|
89
|
+
* JSON (`[ory-agent] {...}`) doesn't interleave with the wizard's
|
|
90
|
+
* human-facing UI when a session runs with `ORY_AGENT_DEBUG=true` (the dev
|
|
91
|
+
* launcher, for one, always sets it). File logging — the real observability
|
|
92
|
+
* channel — is unaffected.
|
|
93
|
+
*/
|
|
94
|
+
static stderrSuppressed = false;
|
|
85
95
|
enabled;
|
|
86
96
|
harness;
|
|
87
97
|
logFile;
|
|
@@ -113,8 +123,13 @@ class DebugLogger {
|
|
|
113
123
|
...(safeData ? { data: safeData } : {}),
|
|
114
124
|
};
|
|
115
125
|
const line = JSON.stringify(entry);
|
|
116
|
-
//
|
|
117
|
-
|
|
126
|
+
// Write to stderr (never stdout) so we don't interfere with hook stdout,
|
|
127
|
+
// unless the stderr firehose is globally suppressed (e.g. during the
|
|
128
|
+
// interactive installer, so it doesn't clutter the wizard UI). The log
|
|
129
|
+
// file below still captures everything.
|
|
130
|
+
if (!DebugLogger.stderrSuppressed) {
|
|
131
|
+
process.stderr.write(`[ory-agent] ${line}\n`);
|
|
132
|
+
}
|
|
118
133
|
if (this.logFile) {
|
|
119
134
|
const dir = path.dirname(this.logFile);
|
|
120
135
|
if (!fs.existsSync(dir)) {
|
|
@@ -137,3 +152,24 @@ class DebugLogger {
|
|
|
137
152
|
}
|
|
138
153
|
}
|
|
139
154
|
exports.DebugLogger = DebugLogger;
|
|
155
|
+
/**
|
|
156
|
+
* Run `fn` with the structured stderr firehose suppressed, restoring the
|
|
157
|
+
* previous state afterward (even on throw). File logging is unaffected.
|
|
158
|
+
*
|
|
159
|
+
* Human-facing CLI commands (the interactive installer, `status`,
|
|
160
|
+
* `permissions status`/`bootstrap`) spin up a client and emit debug/info
|
|
161
|
+
* events; when the process runs with `ORY_AGENT_DEBUG=true` (the dev launcher
|
|
162
|
+
* always sets it) those `[ory-agent] {...}` lines would interleave with the
|
|
163
|
+
* command's polished output. Wrapping the command body in this keeps the
|
|
164
|
+
* terminal clean while the log file still captures everything.
|
|
165
|
+
*/
|
|
166
|
+
async function withQuietStderr(fn) {
|
|
167
|
+
const prev = DebugLogger.stderrSuppressed;
|
|
168
|
+
DebugLogger.stderrSuppressed = true;
|
|
169
|
+
try {
|
|
170
|
+
return await fn();
|
|
171
|
+
}
|
|
172
|
+
finally {
|
|
173
|
+
DebugLogger.stderrSuppressed = prev;
|
|
174
|
+
}
|
|
175
|
+
}
|
package/dist/permissions-cli.js
CHANGED
|
@@ -61,6 +61,7 @@ exports.printPermissionsOnboardingHelp = printPermissionsOnboardingHelp;
|
|
|
61
61
|
exports.maybeAutoBootstrap = maybeAutoBootstrap;
|
|
62
62
|
const config_js_1 = require("./config.js");
|
|
63
63
|
const client_js_1 = require("./client.js");
|
|
64
|
+
const logger_js_1 = require("./logger.js");
|
|
64
65
|
const agent_auth_js_1 = require("./agent-auth.js");
|
|
65
66
|
const auth_store_js_1 = require("./auth-store.js");
|
|
66
67
|
const tool_catalog_js_1 = require("./tool-catalog.js");
|
|
@@ -85,10 +86,14 @@ async function runPermissionsCommand(binName, harness, args) {
|
|
|
85
86
|
return sub ? 0 : 1;
|
|
86
87
|
}
|
|
87
88
|
switch (sub) {
|
|
89
|
+
// `status` and `bootstrap` spin up a client and probe/grant per tool,
|
|
90
|
+
// emitting debug/info events. Quiet the stderr firehose so those don't
|
|
91
|
+
// interleave with the command's human-facing output under
|
|
92
|
+
// ORY_AGENT_DEBUG=true; the log file still captures everything.
|
|
88
93
|
case "status":
|
|
89
|
-
return await runPermissionsStatus(binName, harness);
|
|
94
|
+
return await (0, logger_js_1.withQuietStderr)(() => runPermissionsStatus(binName, harness));
|
|
90
95
|
case "bootstrap":
|
|
91
|
-
return await runPermissionsBootstrap(binName, harness, args.slice(1));
|
|
96
|
+
return await (0, logger_js_1.withQuietStderr)(() => runPermissionsBootstrap(binName, harness, args.slice(1)));
|
|
92
97
|
case "observe":
|
|
93
98
|
return runPermissionsSetMode(binName, "observe");
|
|
94
99
|
case "enforce":
|
|
@@ -283,9 +288,17 @@ async function runPermissionsBootstrap(binName, harness, args) {
|
|
|
283
288
|
continue;
|
|
284
289
|
}
|
|
285
290
|
try {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
291
|
+
// Read-before-write: Keto's create API is not idempotent (every PUT
|
|
292
|
+
// inserts a new row and never 409s), so a plain createRelationship on
|
|
293
|
+
// re-install would duplicate the whole catalog. ensureRelationship
|
|
294
|
+
// probes for the exact tuple first and only writes when it is absent.
|
|
295
|
+
const spanAttributes = { toolName: tool, source: "permissions_bootstrap" };
|
|
296
|
+
let res = await client.ensureRelationship(check, { spanAttributes });
|
|
297
|
+
if (res.probeError) {
|
|
298
|
+
// Couldn't confirm existence — fall back to a direct write so a
|
|
299
|
+
// needed grant is still created (bootstrap's job is to guarantee it).
|
|
300
|
+
res = await client.createRelationship(check, { spanAttributes });
|
|
301
|
+
}
|
|
289
302
|
if (res.alreadyExisted) {
|
|
290
303
|
existed++;
|
|
291
304
|
console.log(` = ${tool} (already exists)`);
|
package/dist/status-cli.js
CHANGED
|
@@ -17,6 +17,7 @@ const config_js_1 = require("./config.js");
|
|
|
17
17
|
const auth_store_js_1 = require("./auth-store.js");
|
|
18
18
|
const agent_auth_js_1 = require("./agent-auth.js");
|
|
19
19
|
const client_js_1 = require("./client.js");
|
|
20
|
+
const logger_js_1 = require("./logger.js");
|
|
20
21
|
const agent_auth_js_2 = require("./agent-auth.js");
|
|
21
22
|
const subject_js_1 = require("./subject.js");
|
|
22
23
|
const tool_catalog_js_1 = require("./tool-catalog.js");
|
|
@@ -279,28 +280,35 @@ function formatModeSuffix(source) {
|
|
|
279
280
|
* than aborting the command.
|
|
280
281
|
*/
|
|
281
282
|
async function runStatusCommand(binName, harness, options) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
283
|
+
// Quiet the structured stderr firehose for the duration of the report so
|
|
284
|
+
// `[ory-agent] {...}` debug lines (the permissions probe runs a client and
|
|
285
|
+
// per-tool checks) don't interleave with this human-facing output when the
|
|
286
|
+
// command runs with ORY_AGENT_DEBUG=true. Debug still lands in the log file,
|
|
287
|
+
// and the "Recent activity" section below surfaces its tail regardless.
|
|
288
|
+
await (0, logger_js_1.withQuietStderr)(async () => {
|
|
289
|
+
const heading = `Ory Agent Plugin Status (${options.title})`;
|
|
290
|
+
console.log(heading);
|
|
291
|
+
console.log("=".repeat(heading.length));
|
|
291
292
|
console.log("");
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
293
|
+
(0, cli_js_1.printOryConfig)();
|
|
294
|
+
printUserIdentitySection();
|
|
295
|
+
printAgentIdentitySection();
|
|
296
|
+
await printPermissionsSection(binName, harness);
|
|
297
|
+
if (options.printPluginSection) {
|
|
298
|
+
console.log("");
|
|
299
|
+
options.printPluginSection();
|
|
300
|
+
}
|
|
301
|
+
(0, cli_js_1.printEnvironment)();
|
|
302
|
+
console.log("");
|
|
303
|
+
console.log("Recent activity:");
|
|
304
|
+
(0, cli_js_1.printTraceTail)(harness);
|
|
305
|
+
(0, cli_js_1.printLogTail)(harness);
|
|
306
|
+
console.log("");
|
|
307
|
+
console.log(` Watch traces live: ${(0, cli_invocation_js_1.oryNpx)(binName)} watch`);
|
|
308
|
+
console.log("");
|
|
309
|
+
console.log(`Drill into any section with:`);
|
|
310
|
+
console.log(` ${(0, cli_invocation_js_1.oryNpx)(binName)} agent status`);
|
|
311
|
+
console.log(` ${(0, cli_invocation_js_1.oryNpx)(binName)} permissions status`);
|
|
312
|
+
console.log(` ${(0, cli_invocation_js_1.oryNpx)(binName)} configure`);
|
|
313
|
+
});
|
|
306
314
|
}
|
package/dist/testing.d.ts
CHANGED
|
@@ -14,6 +14,14 @@ export { runHarnessContractSuite, type HarnessContractAdapter, type ContractCont
|
|
|
14
14
|
* Pass overrides to customize (e.g. a different harness name).
|
|
15
15
|
*/
|
|
16
16
|
export declare function createMockClient(overrides?: Partial<ConstructorParameters<typeof OryAgentClient>[0]>): OryAgentClient;
|
|
17
|
+
/**
|
|
18
|
+
* Control what the exact-tuple existence probe ({@link OryAgentClient.relationshipExists},
|
|
19
|
+
* used by `ensureRelationship`) reports. Pass `true` to model a tuple that is
|
|
20
|
+
* already stored (the write is then skipped), `false` for absent (the write
|
|
21
|
+
* proceeds). Returns the spy so callers can e.g. `.mockRejectedValue(...)` to
|
|
22
|
+
* model a failed probe.
|
|
23
|
+
*/
|
|
24
|
+
export declare function stubRelationshipExists(client: OryAgentClient, exists: boolean): import("vitest").Mock<(check: import("./types.js").PermissionCheck) => Promise<boolean>>;
|
|
17
25
|
/**
|
|
18
26
|
* Stub an internal API instance method on the client.
|
|
19
27
|
* Returns a vi.fn mock so callers can assert on calls.
|
package/dist/testing.js
CHANGED
|
@@ -42,6 +42,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
42
42
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
43
|
exports.BATCH_SERVER_DENIED = exports.BATCH_SERVER_ALLOWED_TOOL_DENIED = exports.BATCH_BOTH_ALLOWED = exports.PERMISSION_DENIED = exports.PERMISSION_ALLOWED = exports.MOCK_INACTIVE_OAUTH2_RESPONSE = exports.MOCK_OAUTH2_RESPONSE = exports.MOCK_INACTIVE_SESSION_RESPONSE = exports.MOCK_SESSION_RESPONSE = exports.runHarnessContractSuite = void 0;
|
|
44
44
|
exports.createMockClient = createMockClient;
|
|
45
|
+
exports.stubRelationshipExists = stubRelationshipExists;
|
|
45
46
|
exports.stubApi = stubApi;
|
|
46
47
|
exports.makeAxiosError = makeAxiosError;
|
|
47
48
|
exports.makeNetworkError = makeNetworkError;
|
|
@@ -85,13 +86,31 @@ Object.defineProperty(exports, "runHarnessContractSuite", { enumerable: true, ge
|
|
|
85
86
|
* Pass overrides to customize (e.g. a different harness name).
|
|
86
87
|
*/
|
|
87
88
|
function createMockClient(overrides) {
|
|
88
|
-
|
|
89
|
+
const client = new client_js_1.OryAgentClient({
|
|
89
90
|
projectUrl: "https://test.projects.oryapis.com",
|
|
90
91
|
apiKey: "test-api-key",
|
|
91
92
|
harness: "test",
|
|
92
93
|
sessionCacheTtlMs: 0,
|
|
93
94
|
...overrides,
|
|
94
95
|
});
|
|
96
|
+
// `ensureRelationship` probes for the exact tuple before writing. Default
|
|
97
|
+
// to "no tuple exists" so a plain createRelationship-asserting test sees the
|
|
98
|
+
// write proceed; tests that model an already-present tuple override this via
|
|
99
|
+
// `stubRelationshipExists`. We spy the public `relationshipExists` method
|
|
100
|
+
// (not the internal getRelationships API) because setAgentPrincipal rebuilds
|
|
101
|
+
// the Keto API instance and would discard an API-level stub.
|
|
102
|
+
vitest_1.vi.spyOn(client, "relationshipExists").mockResolvedValue(false);
|
|
103
|
+
return client;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Control what the exact-tuple existence probe ({@link OryAgentClient.relationshipExists},
|
|
107
|
+
* used by `ensureRelationship`) reports. Pass `true` to model a tuple that is
|
|
108
|
+
* already stored (the write is then skipped), `false` for absent (the write
|
|
109
|
+
* proceeds). Returns the spy so callers can e.g. `.mockRejectedValue(...)` to
|
|
110
|
+
* model a failed probe.
|
|
111
|
+
*/
|
|
112
|
+
function stubRelationshipExists(client, exists) {
|
|
113
|
+
return vitest_1.vi.spyOn(client, "relationshipExists").mockResolvedValue(exists);
|
|
95
114
|
}
|
|
96
115
|
/**
|
|
97
116
|
* Stub an internal API instance method on the client.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ory/argus",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.9",
|
|
4
4
|
"description": "Ory Argus: the core API for building authentication, authorization, and audit into AI agent harness plugins, extensions, and custom integrations",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://ory.com",
|