@ouro.bot/cli 0.1.0-alpha.470 → 0.1.0-alpha.471
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/changelog.json
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
3
|
"versions": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.471",
|
|
6
|
+
"changes": [
|
|
7
|
+
"`ouro account ensure` and `ouro connect mail` can now repair hosted Mail Control registry/vault drift with `--rotate-missing-mail-keys`, storing freshly returned one-time private keys in the owning agent vault without printing them.",
|
|
8
|
+
"Hosted Mail setup now detects missing private key material before writing partial runtime config, rotates only the missing native mailbox and/or delegated source keys, and preserves source separation for native agent mail versus delegated human mail.",
|
|
9
|
+
"Agent Mail setup and recovery docs now teach hosted key rotation explicitly, including that rotation repairs future mail access but cannot decrypt mail already encrypted to a lost private key."
|
|
10
|
+
]
|
|
11
|
+
},
|
|
4
12
|
{
|
|
5
13
|
"version": "0.1.0-alpha.470",
|
|
6
14
|
"changes": [
|
|
@@ -3055,12 +3055,43 @@ function requiredHostedKeyIds(body) {
|
|
|
3055
3055
|
.map((record) => stringField(record, "keyId"))
|
|
3056
3056
|
.filter((keyId) => keyId.length > 0);
|
|
3057
3057
|
}
|
|
3058
|
+
function hostedMissingMailKeys(body, keys) {
|
|
3059
|
+
const mailbox = isPlainRecord(body.mailbox) ? body.mailbox : undefined;
|
|
3060
|
+
const sourceGrant = isPlainRecord(body.sourceGrant) ? body.sourceGrant : undefined;
|
|
3061
|
+
const mailboxKeyId = mailbox ? stringField(mailbox, "keyId") : "";
|
|
3062
|
+
const sourceKeyId = sourceGrant ? stringField(sourceGrant, "keyId") : "";
|
|
3063
|
+
const missingMailbox = mailboxKeyId.length > 0 && !keys[mailboxKeyId];
|
|
3064
|
+
const missingSourceGrant = sourceKeyId.length > 0 && !keys[sourceKeyId];
|
|
3065
|
+
return {
|
|
3066
|
+
keyIds: [
|
|
3067
|
+
...(missingMailbox ? [mailboxKeyId] : []),
|
|
3068
|
+
...(missingSourceGrant ? [sourceKeyId] : []),
|
|
3069
|
+
],
|
|
3070
|
+
rotateMailbox: missingMailbox,
|
|
3071
|
+
rotateSourceGrant: missingSourceGrant,
|
|
3072
|
+
};
|
|
3073
|
+
}
|
|
3058
3074
|
function assertHostedPrivateKeys(input) {
|
|
3059
3075
|
for (const keyId of input.requiredKeyIds) {
|
|
3060
3076
|
if (input.keys[keyId])
|
|
3061
3077
|
continue;
|
|
3062
|
-
throw new Error(`hosted Mail Control references private mail key ${keyId}, but it was not returned and is not present in ${input.agent}'s vault runtime/config. Repair requires a fresh Mail Control one-time key response or
|
|
3078
|
+
throw new Error(`hosted Mail Control references private mail key ${keyId}, but it was not returned and is not present in ${input.agent}'s vault runtime/config. Repair requires a fresh Mail Control one-time key response or rerunning setup with --rotate-missing-mail-keys.`);
|
|
3079
|
+
}
|
|
3080
|
+
}
|
|
3081
|
+
async function requestHostedMailControl(input) {
|
|
3082
|
+
const response = await input.fetchImpl(`${input.config.url}${input.path}`, {
|
|
3083
|
+
method: "POST",
|
|
3084
|
+
headers: {
|
|
3085
|
+
authorization: `Bearer ${input.config.token}`,
|
|
3086
|
+
"content-type": "application/json",
|
|
3087
|
+
},
|
|
3088
|
+
body: JSON.stringify(input.payload),
|
|
3089
|
+
});
|
|
3090
|
+
const body = await response.json();
|
|
3091
|
+
if (!response.ok || body.ok === false) {
|
|
3092
|
+
throw new Error(`hosted Mail Control ${input.label} failed (${response.status}): ${body.error ?? response.statusText}`);
|
|
3063
3093
|
}
|
|
3094
|
+
return body;
|
|
3064
3095
|
}
|
|
3065
3096
|
async function promptDelegatedMailSource(deps, input = {}) {
|
|
3066
3097
|
if (input.noDelegatedSource)
|
|
@@ -3109,38 +3140,52 @@ async function ensureAgentMailroom(agent, input, deps, progressLabel) {
|
|
|
3109
3140
|
if (hostedConfig) {
|
|
3110
3141
|
progress.updateDetail("calling hosted Mail Control");
|
|
3111
3142
|
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
3112
|
-
const
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3143
|
+
const basePayload = {
|
|
3144
|
+
agentId: agent,
|
|
3145
|
+
...(input.ownerEmail ? { ownerEmail: input.ownerEmail } : {}),
|
|
3146
|
+
...(input.source ? { source: input.source } : {}),
|
|
3147
|
+
};
|
|
3148
|
+
let body = await requestHostedMailControl({
|
|
3149
|
+
fetchImpl,
|
|
3150
|
+
config: hostedConfig,
|
|
3151
|
+
path: "/v1/mailboxes/ensure",
|
|
3152
|
+
payload: basePayload,
|
|
3153
|
+
label: "ensure",
|
|
3123
3154
|
});
|
|
3124
|
-
|
|
3125
|
-
if (!response.ok || body.ok === false) {
|
|
3126
|
-
throw new Error(`hosted Mail Control ensure failed (${response.status}): ${body.error ?? response.statusText}`);
|
|
3127
|
-
}
|
|
3128
|
-
const publicRegistry = requiredResponseRecord(body.publicRegistry, "publicRegistry");
|
|
3129
|
-
const blobStore = requiredResponseRecord(body.blobStore, "blobStore");
|
|
3130
|
-
mailboxAddress = typeof body.mailboxAddress === "string" && body.mailboxAddress.trim()
|
|
3131
|
-
? body.mailboxAddress.trim()
|
|
3132
|
-
: requiredResponseText(requiredResponseRecord(body.mailbox, "mailbox"), "canonicalAddress", "mailboxAddress");
|
|
3133
|
-
sourceAlias = typeof body.sourceAlias === "string" && body.sourceAlias.trim() ? body.sourceAlias.trim() : null;
|
|
3134
|
-
const generatedPrivateKeys = responsePrivateKeys(body.generatedPrivateKeys);
|
|
3155
|
+
let generatedPrivateKeys = responsePrivateKeys(body.generatedPrivateKeys);
|
|
3135
3156
|
const privateKeys = {
|
|
3136
3157
|
...mailroomPrivateKeys(existingMailroom),
|
|
3137
3158
|
...generatedPrivateKeys,
|
|
3138
3159
|
};
|
|
3160
|
+
const missingKeys = hostedMissingMailKeys(body, privateKeys);
|
|
3161
|
+
if (missingKeys.keyIds.length > 0 && input.rotateMissingMailKeys) {
|
|
3162
|
+
progress.updateDetail("rotating missing hosted mail keys");
|
|
3163
|
+
body = await requestHostedMailControl({
|
|
3164
|
+
fetchImpl,
|
|
3165
|
+
config: hostedConfig,
|
|
3166
|
+
path: "/v1/mailboxes/rotate-keys",
|
|
3167
|
+
payload: {
|
|
3168
|
+
...basePayload,
|
|
3169
|
+
rotateMailbox: missingKeys.rotateMailbox,
|
|
3170
|
+
rotateSourceGrant: missingKeys.rotateSourceGrant,
|
|
3171
|
+
reason: "missing private mail keys in agent vault",
|
|
3172
|
+
},
|
|
3173
|
+
label: "key rotation",
|
|
3174
|
+
});
|
|
3175
|
+
generatedPrivateKeys = responsePrivateKeys(body.generatedPrivateKeys);
|
|
3176
|
+
Object.assign(privateKeys, generatedPrivateKeys);
|
|
3177
|
+
}
|
|
3139
3178
|
assertHostedPrivateKeys({
|
|
3140
3179
|
agent,
|
|
3141
3180
|
keys: privateKeys,
|
|
3142
3181
|
requiredKeyIds: requiredHostedKeyIds(body),
|
|
3143
3182
|
});
|
|
3183
|
+
const publicRegistry = requiredResponseRecord(body.publicRegistry, "publicRegistry");
|
|
3184
|
+
const blobStore = requiredResponseRecord(body.blobStore, "blobStore");
|
|
3185
|
+
mailboxAddress = typeof body.mailboxAddress === "string" && body.mailboxAddress.trim()
|
|
3186
|
+
? body.mailboxAddress.trim()
|
|
3187
|
+
: requiredResponseText(requiredResponseRecord(body.mailbox, "mailbox"), "canonicalAddress", "mailboxAddress");
|
|
3188
|
+
sourceAlias = typeof body.sourceAlias === "string" && body.sourceAlias.trim() ? body.sourceAlias.trim() : null;
|
|
3144
3189
|
mode = "hosted";
|
|
3145
3190
|
registryPath = null;
|
|
3146
3191
|
storePath = null;
|
|
@@ -3243,7 +3288,10 @@ async function executeConnectMail(agent, deps, input = {}) {
|
|
|
3243
3288
|
],
|
|
3244
3289
|
});
|
|
3245
3290
|
const setup = await promptDelegatedMailSource(deps, input);
|
|
3246
|
-
const outcome = await ensureAgentMailroom(agent,
|
|
3291
|
+
const outcome = await ensureAgentMailroom(agent, {
|
|
3292
|
+
...setup,
|
|
3293
|
+
...(input.rotateMissingMailKeys ? { rotateMissingMailKeys: true } : {}),
|
|
3294
|
+
}, deps, "connect mail");
|
|
3247
3295
|
return writeCapabilityOutcome(deps, {
|
|
3248
3296
|
subtitle: `${agent}'s Mail sense is configured.`,
|
|
3249
3297
|
summary: `Agent Mail is ready for ${agent}.`,
|
|
@@ -3309,7 +3357,10 @@ async function executeAccountEnsure(command, deps) {
|
|
|
3309
3357
|
],
|
|
3310
3358
|
});
|
|
3311
3359
|
const setup = await promptDelegatedMailSource(deps, command);
|
|
3312
|
-
const outcome = await ensureAgentMailroom(command.agent,
|
|
3360
|
+
const outcome = await ensureAgentMailroom(command.agent, {
|
|
3361
|
+
...setup,
|
|
3362
|
+
...(command.rotateMissingMailKeys ? { rotateMissingMailKeys: true } : {}),
|
|
3363
|
+
}, deps, "account ensure");
|
|
3313
3364
|
return writeCapabilityOutcome(deps, {
|
|
3314
3365
|
subtitle: `${command.agent}'s work substrate account is configured.`,
|
|
3315
3366
|
summary: `Ouro work substrate is ready for ${command.agent}.`,
|
|
@@ -313,12 +313,12 @@ const SUBCOMMAND_HELP = {
|
|
|
313
313
|
},
|
|
314
314
|
"connect mail": {
|
|
315
315
|
description: "Provision portable Agent Mail / Mailroom access and enable the Mail sense",
|
|
316
|
-
usage: "ouro connect mail [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source]",
|
|
316
|
+
usage: "ouro connect mail [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source] [--rotate-missing-mail-keys]",
|
|
317
317
|
example: "ouro connect mail --agent slugger --owner-email ari@mendelow.me --source hey",
|
|
318
318
|
},
|
|
319
319
|
"account ensure": {
|
|
320
320
|
description: "Idempotently prepare an agent's vault-backed work substrate account and private Mailroom mailbox",
|
|
321
|
-
usage: "ouro account ensure [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source]",
|
|
321
|
+
usage: "ouro account ensure [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source] [--rotate-missing-mail-keys]",
|
|
322
322
|
example: "ouro account ensure --agent slugger --owner-email ari@mendelow.me --source hey",
|
|
323
323
|
},
|
|
324
324
|
"mail import-mbox": {
|
|
@@ -84,8 +84,8 @@ function usage() {
|
|
|
84
84
|
" ouro config model [--agent <name>] <model-name>",
|
|
85
85
|
" ouro config models [--agent <name>]",
|
|
86
86
|
" ouro auth [--agent <name>] [--provider <provider>]",
|
|
87
|
-
" ouro account ensure [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source]",
|
|
88
|
-
" ouro connect [providers|perplexity|embeddings|teams|bluebubbles|mail] [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source]",
|
|
87
|
+
" ouro account ensure [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source] [--rotate-missing-mail-keys]",
|
|
88
|
+
" ouro connect [providers|perplexity|embeddings|teams|bluebubbles|mail] [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source] [--rotate-missing-mail-keys]",
|
|
89
89
|
" ouro mail import-mbox --file <path> [--owner-email <email>] [--source <label>] [--agent <name>]",
|
|
90
90
|
" ouro auth verify [--agent <name>] [--provider <provider>]",
|
|
91
91
|
" ouro auth switch [--agent <name>] --provider <provider>",
|
|
@@ -817,6 +817,7 @@ function extractMailSourceFlags(args, usageText) {
|
|
|
817
817
|
let ownerEmail;
|
|
818
818
|
let source;
|
|
819
819
|
let noDelegatedSource = false;
|
|
820
|
+
let rotateMissingMailKeys = false;
|
|
820
821
|
let hasMailSourceFlags = false;
|
|
821
822
|
for (let i = 0; i < args.length; i += 1) {
|
|
822
823
|
const token = args[i];
|
|
@@ -839,6 +840,11 @@ function extractMailSourceFlags(args, usageText) {
|
|
|
839
840
|
hasMailSourceFlags = true;
|
|
840
841
|
continue;
|
|
841
842
|
}
|
|
843
|
+
if (token === "--rotate-missing-mail-keys") {
|
|
844
|
+
rotateMissingMailKeys = true;
|
|
845
|
+
hasMailSourceFlags = true;
|
|
846
|
+
continue;
|
|
847
|
+
}
|
|
842
848
|
rest.push(token);
|
|
843
849
|
}
|
|
844
850
|
if (noDelegatedSource && (ownerEmail !== undefined || source !== undefined)) {
|
|
@@ -852,11 +858,12 @@ function extractMailSourceFlags(args, usageText) {
|
|
|
852
858
|
...(ownerEmail !== undefined ? { ownerEmail } : {}),
|
|
853
859
|
...(source !== undefined ? { source } : {}),
|
|
854
860
|
...(noDelegatedSource ? { noDelegatedSource: true } : {}),
|
|
861
|
+
...(rotateMissingMailKeys ? { rotateMissingMailKeys: true } : {}),
|
|
855
862
|
hasMailSourceFlags,
|
|
856
863
|
};
|
|
857
864
|
}
|
|
858
865
|
function parseConnectCommand(args) {
|
|
859
|
-
const usageText = "Usage: ouro connect [providers|perplexity|embeddings|teams|bluebubbles|mail] [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source]";
|
|
866
|
+
const usageText = "Usage: ouro connect [providers|perplexity|embeddings|teams|bluebubbles|mail] [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source] [--rotate-missing-mail-keys]";
|
|
860
867
|
const { agent, rest: afterAgent } = extractAgentFlag(args);
|
|
861
868
|
const mailFlags = extractMailSourceFlags(afterAgent, usageText);
|
|
862
869
|
if (mailFlags.rest.length > 1)
|
|
@@ -872,6 +879,7 @@ function parseConnectCommand(args) {
|
|
|
872
879
|
...(mailFlags.ownerEmail !== undefined ? { ownerEmail: mailFlags.ownerEmail } : {}),
|
|
873
880
|
...(mailFlags.source !== undefined ? { source: mailFlags.source } : {}),
|
|
874
881
|
...(mailFlags.noDelegatedSource ? { noDelegatedSource: true } : {}),
|
|
882
|
+
...(mailFlags.rotateMissingMailKeys ? { rotateMissingMailKeys: true } : {}),
|
|
875
883
|
};
|
|
876
884
|
}
|
|
877
885
|
function parseMailCommand(args) {
|
|
@@ -912,7 +920,7 @@ function parseMailCommand(args) {
|
|
|
912
920
|
}
|
|
913
921
|
function parseAccountCommand(args) {
|
|
914
922
|
const [sub, ...subArgs] = args;
|
|
915
|
-
const usageText = "Usage: ouro account ensure [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source]";
|
|
923
|
+
const usageText = "Usage: ouro account ensure [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source] [--rotate-missing-mail-keys]";
|
|
916
924
|
if (sub !== "ensure") {
|
|
917
925
|
throw new Error(usageText);
|
|
918
926
|
}
|
|
@@ -926,6 +934,7 @@ function parseAccountCommand(args) {
|
|
|
926
934
|
...(mailFlags.ownerEmail !== undefined ? { ownerEmail: mailFlags.ownerEmail } : {}),
|
|
927
935
|
...(mailFlags.source !== undefined ? { source: mailFlags.source } : {}),
|
|
928
936
|
...(mailFlags.noDelegatedSource ? { noDelegatedSource: true } : {}),
|
|
937
|
+
...(mailFlags.rotateMissingMailKeys ? { rotateMissingMailKeys: true } : {}),
|
|
929
938
|
};
|
|
930
939
|
}
|
|
931
940
|
function parseProviderUseCommand(args) {
|