@ours.network/codex 0.18.0-nightly.4 → 0.18.0-nightly.6
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/.codex-plugin/plugin.json +1 -1
- package/.mcp.json +1 -1
- package/README.md +3 -0
- package/bin/codex-legacy-cleanup.mjs +19 -9
- package/bin/proxy.mjs +6 -3
- package/dist/monitor-mcp.mjs +416 -124
- package/hooks/hooks.json +13 -1
- package/install.sh +7 -2
- package/package.json +3 -3
- package/skills/ours/SKILL.md +9 -7
- package/src/hooks/runner.mjs +1 -1
- package/src/launcher.mjs +20 -1
package/.mcp.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"command": "node",
|
|
5
5
|
"args": ["bin/proxy.mjs"],
|
|
6
6
|
"cwd": ".",
|
|
7
|
-
"env_vars": ["OURS_PORT", "OURS_CONFIG", "OURS_API_TOKEN", "OURS_STATE_DIR", "OURS_AUTOSTART", "OURS_CODEX_LIVE"]
|
|
7
|
+
"env_vars": ["OURS_PORT", "OURS_CONFIG", "OURS_API_TOKEN", "OURS_STATE_DIR", "OURS_AUTOSTART", "OURS_CODEX_LIVE", "OURS_CLIENT_PID"]
|
|
8
8
|
},
|
|
9
9
|
"ours_monitor": {
|
|
10
10
|
"command": "node",
|
package/README.md
CHANGED
|
@@ -77,6 +77,9 @@ lifecycle directly, while the hooks add standard-mode context and defensive stat
|
|
|
77
77
|
- `SessionStart` surfaces body-free unread metadata and an advisory `.ours-identity` pin.
|
|
78
78
|
- `UserPromptSubmit` can re-surface unresolved unread/pin context.
|
|
79
79
|
- `PostToolUse` records successful identity bindings and disarms on a switch.
|
|
80
|
+
- `SessionEnd` releases the session lease and waits for all session-owned temporary
|
|
81
|
+
roles to send best-effort removal notices and delete local state. Live mode also
|
|
82
|
+
invokes this cleanup directly when its TUI exits, so it does not depend on hook trust.
|
|
80
83
|
|
|
81
84
|
Codex requires review and trust of the exact hook definitions before running them.
|
|
82
85
|
Installation does not bypass hook trust, and live monitoring remains available when the
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { readFileSync, writeFileSync, existsSync, renameSync,
|
|
2
|
+
import { readFileSync, writeFileSync, existsSync, renameSync, realpathSync } from 'node:fs';
|
|
3
3
|
import { resolve, join } from 'node:path';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
5
6
|
|
|
6
7
|
const codexDir = resolve(process.env.CODEX_DIR || process.env.CODEX_HOME || join(homedir(), '.codex'));
|
|
7
8
|
const skillsDir = resolve(process.env.SKILLS_DIR || join(homedir(), '.agents', 'skills'));
|
|
@@ -42,13 +43,22 @@ function stripOrphanedMcpConfig(path) {
|
|
|
42
43
|
return true;
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
if (!
|
|
47
|
-
|
|
46
|
+
export function backupLegacySkill(path, backup, rename = renameSync) {
|
|
47
|
+
if (!existsSync(path)) return false;
|
|
48
|
+
rename(path, backup);
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
48
51
|
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
if (!
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
function main() {
|
|
53
|
+
const configPath = join(codexDir, 'config.toml');
|
|
54
|
+
if (!stripManaged(configPath, '# >>> ours.network plugin', '# <<< ours.network plugin')) stripOrphanedMcpConfig(configPath);
|
|
55
|
+
stripManaged(join(codexDir, 'AGENTS.md'), '<!-- >>> ours.network plugin', '<!-- <<< ours.network plugin -->');
|
|
56
|
+
|
|
57
|
+
for (const name of ['ours', 'writing-agent-bios']) {
|
|
58
|
+
const path = join(skillsDir, name);
|
|
59
|
+
backupLegacySkill(path, `${path}.ours-legacy-${stamp}`);
|
|
60
|
+
}
|
|
54
61
|
}
|
|
62
|
+
|
|
63
|
+
const invokedDirectly = process.argv[1] && realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url));
|
|
64
|
+
if (invokedDirectly) main();
|
package/bin/proxy.mjs
CHANGED
|
@@ -22,9 +22,12 @@ if (!cliPath) {
|
|
|
22
22
|
}
|
|
23
23
|
const env = { ...process.env };
|
|
24
24
|
if (env.OURS_CODEX_LIVE === '1') env.OURS_AUTOSTART = '0';
|
|
25
|
-
if (process.ppid > 1) env.OURS_CLIENT_PID = String(process.ppid);
|
|
25
|
+
if (!env.OURS_CLIENT_PID && process.ppid > 1) env.OURS_CLIENT_PID = String(process.ppid);
|
|
26
|
+
const sessionEnd = process.argv[2] === 'session-end';
|
|
27
|
+
const command = sessionEnd ? 'session-end' : 'proxy';
|
|
28
|
+
const forwarded = process.argv.slice(sessionEnd ? 3 : 2);
|
|
26
29
|
const child = cliPath
|
|
27
|
-
? spawn(process.execPath, [cliPath,
|
|
28
|
-
: spawn('ours-mcp', [
|
|
30
|
+
? spawn(process.execPath, [cliPath, command, ...forwarded], { stdio: 'inherit', env })
|
|
31
|
+
: spawn('ours-mcp', [command, ...forwarded], { stdio: 'inherit', env });
|
|
29
32
|
child.on('error', (error) => { process.stderr.write(`ours: cannot launch @ours.network/mcp proxy: ${error.message}\n`); process.exit(1); });
|
|
30
33
|
child.on('exit', (code, signal) => { if (signal) process.kill(process.pid, signal); else process.exit(code ?? 0); });
|
package/dist/monitor-mcp.mjs
CHANGED
|
@@ -3106,7 +3106,25 @@ var require_utils = __commonJS({
|
|
|
3106
3106
|
var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
|
|
3107
3107
|
var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
|
|
3108
3108
|
var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
|
|
3109
|
-
var isPathCharacter = RegExp.prototype.test.bind(/^[
|
|
3109
|
+
var isPathCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/]$/u);
|
|
3110
|
+
var isQueryFragmentCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/?]$/u);
|
|
3111
|
+
var isUserinfoCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:]$/u);
|
|
3112
|
+
var BYTE_HEX = new Array(256);
|
|
3113
|
+
{
|
|
3114
|
+
const HEX_DIGITS = "0123456789ABCDEF";
|
|
3115
|
+
for (let i = 0; i < 256; i++) {
|
|
3116
|
+
BYTE_HEX[i] = "%" + HEX_DIGITS[i >> 4] + HEX_DIGITS[i & 15];
|
|
3117
|
+
}
|
|
3118
|
+
}
|
|
3119
|
+
function percentEncodeNonAscii(cp) {
|
|
3120
|
+
if (cp < 2048) {
|
|
3121
|
+
return BYTE_HEX[192 | cp >> 6] + BYTE_HEX[128 | cp & 63];
|
|
3122
|
+
}
|
|
3123
|
+
if (cp < 65536) {
|
|
3124
|
+
return BYTE_HEX[224 | cp >> 12] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63];
|
|
3125
|
+
}
|
|
3126
|
+
return BYTE_HEX[240 | cp >> 18] + BYTE_HEX[128 | cp >> 12 & 63] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63];
|
|
3127
|
+
}
|
|
3110
3128
|
function stringArrayToHexStripped(input) {
|
|
3111
3129
|
let acc = "";
|
|
3112
3130
|
let code = 0;
|
|
@@ -3131,91 +3149,105 @@ var require_utils = __commonJS({
|
|
|
3131
3149
|
}
|
|
3132
3150
|
return acc;
|
|
3133
3151
|
}
|
|
3152
|
+
var isHextet = RegExp.prototype.test.bind(/^[\dA-Fa-f]{1,4}$/);
|
|
3153
|
+
var isIPvFuture = RegExp.prototype.test.bind(/^[vV][\dA-Fa-f]+\.[A-Za-z\d\-._~!$&'()*+,;=:]+$/);
|
|
3154
|
+
var isZoneCharacter = RegExp.prototype.test.bind(/^[A-Za-z\d\-._~]$/);
|
|
3134
3155
|
var nonSimpleDomain = RegExp.prototype.test.bind(/[^!"$&'()*+,\-.;=_`a-z{}~]/u);
|
|
3135
|
-
function
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
if (hex !== "") {
|
|
3143
|
-
address.push(hex);
|
|
3144
|
-
} else {
|
|
3145
|
-
output.error = true;
|
|
3146
|
-
return false;
|
|
3156
|
+
function isZoneIdentifier(zone) {
|
|
3157
|
+
if (zone.length === 0) return false;
|
|
3158
|
+
for (let i = 0; i < zone.length; i++) {
|
|
3159
|
+
if (isZoneCharacter(zone[i])) continue;
|
|
3160
|
+
if (zone[i] === "%" && i + 2 < zone.length && isHexPair(zone.slice(i + 1, i + 3))) {
|
|
3161
|
+
i += 2;
|
|
3162
|
+
continue;
|
|
3147
3163
|
}
|
|
3148
|
-
|
|
3164
|
+
return false;
|
|
3149
3165
|
}
|
|
3150
3166
|
return true;
|
|
3151
3167
|
}
|
|
3152
|
-
function
|
|
3153
|
-
let
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
let
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
}
|
|
3165
|
-
if (cursor === ":") {
|
|
3166
|
-
if (endipv6Encountered === true) {
|
|
3167
|
-
endIpv6 = true;
|
|
3168
|
-
}
|
|
3169
|
-
if (!consume(buffer, address, output)) {
|
|
3170
|
-
break;
|
|
3171
|
-
}
|
|
3172
|
-
if (++tokenCount > 7) {
|
|
3173
|
-
output.error = true;
|
|
3174
|
-
break;
|
|
3168
|
+
function compressIPv6ZeroRun(hextets) {
|
|
3169
|
+
let bestStart = -1;
|
|
3170
|
+
let bestLength = 0;
|
|
3171
|
+
let runStart = -1;
|
|
3172
|
+
let runLength = 0;
|
|
3173
|
+
for (let i = 0; i < hextets.length; i++) {
|
|
3174
|
+
if (hextets[i] === "0") {
|
|
3175
|
+
if (runStart === -1) runStart = i;
|
|
3176
|
+
runLength++;
|
|
3177
|
+
if (runLength > bestLength) {
|
|
3178
|
+
bestLength = runLength;
|
|
3179
|
+
bestStart = runStart;
|
|
3175
3180
|
}
|
|
3176
|
-
if (i > 0 && input[i - 1] === ":") {
|
|
3177
|
-
endipv6Encountered = true;
|
|
3178
|
-
}
|
|
3179
|
-
address.push(":");
|
|
3180
|
-
continue;
|
|
3181
|
-
} else if (cursor === "%") {
|
|
3182
|
-
if (!consume(buffer, address, output)) {
|
|
3183
|
-
break;
|
|
3184
|
-
}
|
|
3185
|
-
consume = consumeIsZone;
|
|
3186
3181
|
} else {
|
|
3187
|
-
|
|
3182
|
+
runStart = -1;
|
|
3183
|
+
runLength = 0;
|
|
3184
|
+
}
|
|
3185
|
+
}
|
|
3186
|
+
if (bestLength < 2) return hextets.join(":");
|
|
3187
|
+
const head = hextets.slice(0, bestStart).join(":");
|
|
3188
|
+
const tail = hextets.slice(bestStart + bestLength).join(":");
|
|
3189
|
+
return head + "::" + tail;
|
|
3190
|
+
}
|
|
3191
|
+
function normalizeIPv6Address(input) {
|
|
3192
|
+
const compression = input.indexOf("::");
|
|
3193
|
+
if (compression !== -1 && input.indexOf("::", compression + 1) !== -1) return void 0;
|
|
3194
|
+
const left = compression === -1 ? input.split(":") : input.slice(0, compression).split(":");
|
|
3195
|
+
const right = compression === -1 ? [] : input.slice(compression + 2).split(":");
|
|
3196
|
+
if (compression !== -1) {
|
|
3197
|
+
if (left.length === 1 && left[0] === "") left.length = 0;
|
|
3198
|
+
if (right.length === 1 && right[0] === "") right.length = 0;
|
|
3199
|
+
}
|
|
3200
|
+
const parts = left.concat(right);
|
|
3201
|
+
let hextetCount = 0;
|
|
3202
|
+
for (let i = 0; i < parts.length; i++) {
|
|
3203
|
+
const part = parts[i];
|
|
3204
|
+
if (part === "") return void 0;
|
|
3205
|
+
if (part.indexOf(".") !== -1) {
|
|
3206
|
+
if (i !== parts.length - 1 || compression !== -1 && right.length === 0 || !isIPv4(part)) return void 0;
|
|
3207
|
+
hextetCount += 2;
|
|
3188
3208
|
continue;
|
|
3189
3209
|
}
|
|
3210
|
+
if (!isHextet(part)) return void 0;
|
|
3211
|
+
parts[i] = parseInt(part, 16).toString(16);
|
|
3212
|
+
hextetCount++;
|
|
3190
3213
|
}
|
|
3191
|
-
if (
|
|
3192
|
-
if (
|
|
3193
|
-
|
|
3194
|
-
} else if (endIpv6) {
|
|
3195
|
-
address.push(buffer.join(""));
|
|
3196
|
-
} else {
|
|
3197
|
-
address.push(stringArrayToHexStripped(buffer));
|
|
3198
|
-
}
|
|
3214
|
+
if (compression === -1) {
|
|
3215
|
+
if (hextetCount !== 8) return void 0;
|
|
3216
|
+
return compressIPv6ZeroRun(parts);
|
|
3199
3217
|
}
|
|
3200
|
-
|
|
3201
|
-
|
|
3218
|
+
if (hextetCount >= 8) return void 0;
|
|
3219
|
+
const expanded = parts.slice(0, left.length);
|
|
3220
|
+
for (let i = hextetCount; i < 8; i++) expanded.push("0");
|
|
3221
|
+
for (let i = left.length; i < parts.length; i++) expanded.push(parts[i]);
|
|
3222
|
+
return compressIPv6ZeroRun(expanded);
|
|
3202
3223
|
}
|
|
3203
3224
|
function normalizeIPv6(host) {
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
}
|
|
3207
|
-
|
|
3208
|
-
if (
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3225
|
+
const bracketed = host[0] === "[" && host[host.length - 1] === "]";
|
|
3226
|
+
const hasBracket = host[0] === "[" || host[host.length - 1] === "]";
|
|
3227
|
+
if (hasBracket && !bracketed) return { host, isIPV6: false, error: true };
|
|
3228
|
+
let input = bracketed ? host.slice(1, -1) : host;
|
|
3229
|
+
if (bracketed && isIPvFuture(input)) {
|
|
3230
|
+
input = input.toLowerCase();
|
|
3231
|
+
return { host: `[${input}]`, escapedHost: input, isIPV6: false, isIPVFuture: true };
|
|
3232
|
+
}
|
|
3233
|
+
if (findToken(input, ":") < 2) {
|
|
3234
|
+
return { host, isIPV6: false, error: bracketed };
|
|
3235
|
+
}
|
|
3236
|
+
let zoneIdentifier = "";
|
|
3237
|
+
const zoneSeparator = input.indexOf("%");
|
|
3238
|
+
if (zoneSeparator !== -1) {
|
|
3239
|
+
const separatorLength = input.slice(zoneSeparator, zoneSeparator + 3).toLowerCase() === "%25" ? 3 : 1;
|
|
3240
|
+
zoneIdentifier = input.slice(zoneSeparator + separatorLength);
|
|
3241
|
+
if (!isZoneIdentifier(zoneIdentifier)) return { host, isIPV6: false, error: true };
|
|
3242
|
+
input = input.slice(0, zoneSeparator);
|
|
3243
|
+
}
|
|
3244
|
+
const address = normalizeIPv6Address(input);
|
|
3245
|
+
if (address === void 0) return { host, isIPV6: false, error: true };
|
|
3246
|
+
return {
|
|
3247
|
+
host: address + (zoneIdentifier ? "%" + zoneIdentifier : ""),
|
|
3248
|
+
escapedHost: address + (zoneIdentifier ? "%25" + zoneIdentifier : ""),
|
|
3249
|
+
isIPV6: true
|
|
3250
|
+
};
|
|
3219
3251
|
}
|
|
3220
3252
|
function findToken(str, token) {
|
|
3221
3253
|
let ind = 0;
|
|
@@ -3334,7 +3366,8 @@ var require_utils = __commonJS({
|
|
|
3334
3366
|
function normalizePathEncoding(input) {
|
|
3335
3367
|
let output = "";
|
|
3336
3368
|
for (let i = 0; i < input.length; i++) {
|
|
3337
|
-
|
|
3369
|
+
const ch = input[i];
|
|
3370
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3338
3371
|
const hex = input.slice(i + 1, i + 3);
|
|
3339
3372
|
if (isHexPair(hex)) {
|
|
3340
3373
|
const normalizedHex = hex.toUpperCase();
|
|
@@ -3348,10 +3381,152 @@ var require_utils = __commonJS({
|
|
|
3348
3381
|
continue;
|
|
3349
3382
|
}
|
|
3350
3383
|
}
|
|
3351
|
-
if (isPathCharacter(
|
|
3352
|
-
output +=
|
|
3384
|
+
if (isPathCharacter(ch)) {
|
|
3385
|
+
output += ch;
|
|
3386
|
+
} else {
|
|
3387
|
+
const code = input.charCodeAt(i);
|
|
3388
|
+
if (code < 128) {
|
|
3389
|
+
output += isEscapeSafe(code) ? ch : BYTE_HEX[code];
|
|
3390
|
+
} else if (code < 55296 || code > 57343) {
|
|
3391
|
+
output += percentEncodeNonAscii(code);
|
|
3392
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3393
|
+
const low = input.charCodeAt(i + 1);
|
|
3394
|
+
if (low >= 56320 && low <= 57343) {
|
|
3395
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3396
|
+
i++;
|
|
3397
|
+
} else {
|
|
3398
|
+
output += percentEncodeNonAscii(65533);
|
|
3399
|
+
}
|
|
3400
|
+
} else {
|
|
3401
|
+
output += percentEncodeNonAscii(65533);
|
|
3402
|
+
}
|
|
3403
|
+
}
|
|
3404
|
+
}
|
|
3405
|
+
return output;
|
|
3406
|
+
}
|
|
3407
|
+
function serializePathEncoding(input, pathNoScheme = false) {
|
|
3408
|
+
let output = "";
|
|
3409
|
+
let firstSegment = pathNoScheme && input[0] !== "/";
|
|
3410
|
+
for (let i = 0; i < input.length; i++) {
|
|
3411
|
+
const ch = input[i];
|
|
3412
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3413
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3414
|
+
if (isHexPair(hex)) {
|
|
3415
|
+
output += "%" + hex.toUpperCase();
|
|
3416
|
+
i += 2;
|
|
3417
|
+
continue;
|
|
3418
|
+
}
|
|
3419
|
+
}
|
|
3420
|
+
if (ch === "/") {
|
|
3421
|
+
firstSegment = false;
|
|
3422
|
+
}
|
|
3423
|
+
if (isPathCharacter(ch) && (ch !== ":" || !firstSegment)) {
|
|
3424
|
+
output += ch;
|
|
3425
|
+
} else {
|
|
3426
|
+
const code = input.charCodeAt(i);
|
|
3427
|
+
if (code < 128) {
|
|
3428
|
+
output += BYTE_HEX[code];
|
|
3429
|
+
} else if (code < 55296 || code > 57343) {
|
|
3430
|
+
output += percentEncodeNonAscii(code);
|
|
3431
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3432
|
+
const low = input.charCodeAt(i + 1);
|
|
3433
|
+
if (low >= 56320 && low <= 57343) {
|
|
3434
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3435
|
+
i++;
|
|
3436
|
+
} else {
|
|
3437
|
+
output += percentEncodeNonAscii(65533);
|
|
3438
|
+
}
|
|
3439
|
+
} else {
|
|
3440
|
+
output += percentEncodeNonAscii(65533);
|
|
3441
|
+
}
|
|
3442
|
+
}
|
|
3443
|
+
}
|
|
3444
|
+
return output;
|
|
3445
|
+
}
|
|
3446
|
+
function encodeComponent(input, isAllowed) {
|
|
3447
|
+
let output = "";
|
|
3448
|
+
for (let i = 0; i < input.length; i++) {
|
|
3449
|
+
const ch = input[i];
|
|
3450
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3451
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3452
|
+
if (isHexPair(hex)) {
|
|
3453
|
+
output += "%" + hex.toUpperCase();
|
|
3454
|
+
i += 2;
|
|
3455
|
+
continue;
|
|
3456
|
+
}
|
|
3457
|
+
}
|
|
3458
|
+
if (isAllowed(ch)) {
|
|
3459
|
+
output += ch;
|
|
3353
3460
|
} else {
|
|
3354
|
-
|
|
3461
|
+
const code = input.charCodeAt(i);
|
|
3462
|
+
if (code < 128) {
|
|
3463
|
+
output += BYTE_HEX[code];
|
|
3464
|
+
} else if (code < 55296 || code > 57343) {
|
|
3465
|
+
output += percentEncodeNonAscii(code);
|
|
3466
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3467
|
+
const low = input.charCodeAt(i + 1);
|
|
3468
|
+
if (low >= 56320 && low <= 57343) {
|
|
3469
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3470
|
+
i++;
|
|
3471
|
+
} else {
|
|
3472
|
+
output += percentEncodeNonAscii(65533);
|
|
3473
|
+
}
|
|
3474
|
+
} else {
|
|
3475
|
+
output += percentEncodeNonAscii(65533);
|
|
3476
|
+
}
|
|
3477
|
+
}
|
|
3478
|
+
}
|
|
3479
|
+
return output;
|
|
3480
|
+
}
|
|
3481
|
+
function encodeUserinfo(input) {
|
|
3482
|
+
return encodeComponent(input, isUserinfoCharacter);
|
|
3483
|
+
}
|
|
3484
|
+
function encodeQuery(input) {
|
|
3485
|
+
return encodeComponent(input, isQueryFragmentCharacter);
|
|
3486
|
+
}
|
|
3487
|
+
function encodeFragment(input) {
|
|
3488
|
+
return encodeComponent(input, isQueryFragmentCharacter);
|
|
3489
|
+
}
|
|
3490
|
+
function isEscapeSafe(cp) {
|
|
3491
|
+
return cp >= 48 && cp <= 57 || cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122 || cp === 42 || cp === 43 || cp === 45 || cp === 46 || cp === 47 || cp === 64 || cp === 95;
|
|
3492
|
+
}
|
|
3493
|
+
function normalizeQueryFragmentEncoding(input) {
|
|
3494
|
+
let output = "";
|
|
3495
|
+
for (let i = 0; i < input.length; i++) {
|
|
3496
|
+
const ch = input[i];
|
|
3497
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3498
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3499
|
+
if (isHexPair(hex)) {
|
|
3500
|
+
const normalizedHex = hex.toUpperCase();
|
|
3501
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
3502
|
+
if (isUnreserved(decoded)) {
|
|
3503
|
+
output += decoded;
|
|
3504
|
+
} else {
|
|
3505
|
+
output += "%" + normalizedHex;
|
|
3506
|
+
}
|
|
3507
|
+
i += 2;
|
|
3508
|
+
continue;
|
|
3509
|
+
}
|
|
3510
|
+
}
|
|
3511
|
+
if (isQueryFragmentCharacter(ch)) {
|
|
3512
|
+
output += ch;
|
|
3513
|
+
} else {
|
|
3514
|
+
const code = input.charCodeAt(i);
|
|
3515
|
+
if (code < 128) {
|
|
3516
|
+
output += isEscapeSafe(code) ? ch : BYTE_HEX[code];
|
|
3517
|
+
} else if (code < 55296 || code > 57343) {
|
|
3518
|
+
output += percentEncodeNonAscii(code);
|
|
3519
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3520
|
+
const low = input.charCodeAt(i + 1);
|
|
3521
|
+
if (low >= 56320 && low <= 57343) {
|
|
3522
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3523
|
+
i++;
|
|
3524
|
+
} else {
|
|
3525
|
+
output += percentEncodeNonAscii(65533);
|
|
3526
|
+
}
|
|
3527
|
+
} else {
|
|
3528
|
+
output += percentEncodeNonAscii(65533);
|
|
3529
|
+
}
|
|
3355
3530
|
}
|
|
3356
3531
|
}
|
|
3357
3532
|
return output;
|
|
@@ -3374,14 +3549,18 @@ var require_utils = __commonJS({
|
|
|
3374
3549
|
function recomposeAuthority(component) {
|
|
3375
3550
|
const uriTokens = [];
|
|
3376
3551
|
if (component.userinfo !== void 0) {
|
|
3377
|
-
uriTokens.push(component.userinfo);
|
|
3552
|
+
uriTokens.push(encodeUserinfo(component.userinfo));
|
|
3378
3553
|
uriTokens.push("@");
|
|
3379
3554
|
}
|
|
3380
3555
|
if (component.host !== void 0) {
|
|
3381
|
-
let host =
|
|
3556
|
+
let host = component.host;
|
|
3382
3557
|
if (!isIPv4(host)) {
|
|
3383
|
-
|
|
3384
|
-
if (ipV6res.isIPV6
|
|
3558
|
+
let ipV6res = normalizeIPv6(host);
|
|
3559
|
+
if (ipV6res.isIPV6 !== true && ipV6res.isIPVFuture !== true) {
|
|
3560
|
+
host = normalizePercentEncoding(host, true);
|
|
3561
|
+
ipV6res = normalizeIPv6(host);
|
|
3562
|
+
}
|
|
3563
|
+
if (ipV6res.isIPV6 === true || ipV6res.isIPVFuture === true) {
|
|
3385
3564
|
host = `[${ipV6res.escapedHost}]`;
|
|
3386
3565
|
} else {
|
|
3387
3566
|
host = reescapeHostDelimiters(host, false);
|
|
@@ -3401,6 +3580,11 @@ var require_utils = __commonJS({
|
|
|
3401
3580
|
reescapeHostDelimiters,
|
|
3402
3581
|
normalizePercentEncoding,
|
|
3403
3582
|
normalizePathEncoding,
|
|
3583
|
+
serializePathEncoding,
|
|
3584
|
+
normalizeQueryFragmentEncoding,
|
|
3585
|
+
encodeUserinfo,
|
|
3586
|
+
encodeQuery,
|
|
3587
|
+
encodeFragment,
|
|
3404
3588
|
escapePreservingEscapes,
|
|
3405
3589
|
removeDotSegments,
|
|
3406
3590
|
isIPv4,
|
|
@@ -3416,7 +3600,7 @@ var require_schemes = __commonJS({
|
|
|
3416
3600
|
"../../node_modules/fast-uri/lib/schemes.js"(exports, module) {
|
|
3417
3601
|
"use strict";
|
|
3418
3602
|
var { isUUID } = require_utils();
|
|
3419
|
-
var URN_REG =
|
|
3603
|
+
var URN_REG = /^([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-./:;=@]|%[\da-f]{2})+)$/iu;
|
|
3420
3604
|
var supportedSchemeNames = (
|
|
3421
3605
|
/** @type {const} */
|
|
3422
3606
|
[
|
|
@@ -3477,9 +3661,10 @@ var require_schemes = __commonJS({
|
|
|
3477
3661
|
wsComponent.secure = void 0;
|
|
3478
3662
|
}
|
|
3479
3663
|
if (wsComponent.resourceName) {
|
|
3480
|
-
const
|
|
3664
|
+
const queryIndex = wsComponent.resourceName.indexOf("?");
|
|
3665
|
+
const path = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
|
|
3481
3666
|
wsComponent.path = path && path !== "/" ? path : void 0;
|
|
3482
|
-
wsComponent.query =
|
|
3667
|
+
wsComponent.query = queryIndex === -1 ? void 0 : wsComponent.resourceName.slice(queryIndex + 1);
|
|
3483
3668
|
wsComponent.resourceName = void 0;
|
|
3484
3669
|
}
|
|
3485
3670
|
wsComponent.fragment = void 0;
|
|
@@ -3491,7 +3676,7 @@ var require_schemes = __commonJS({
|
|
|
3491
3676
|
return urnComponent;
|
|
3492
3677
|
}
|
|
3493
3678
|
const matches = urnComponent.path.match(URN_REG);
|
|
3494
|
-
if (matches) {
|
|
3679
|
+
if (matches && matches[0] === urnComponent.path) {
|
|
3495
3680
|
const scheme = options.scheme || urnComponent.scheme || "urn";
|
|
3496
3681
|
urnComponent.nid = matches[1].toLowerCase();
|
|
3497
3682
|
urnComponent.nss = matches[2];
|
|
@@ -3625,8 +3810,17 @@ var require_schemes = __commonJS({
|
|
|
3625
3810
|
var require_fast_uri = __commonJS({
|
|
3626
3811
|
"../../node_modules/fast-uri/index.js"(exports, module) {
|
|
3627
3812
|
"use strict";
|
|
3628
|
-
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding,
|
|
3813
|
+
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
|
|
3629
3814
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
3815
|
+
var VALID_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*$/u;
|
|
3816
|
+
var MALFORMED_SCHEME_ERROR = "URI scheme is malformed.";
|
|
3817
|
+
function decodeValidScheme(scheme) {
|
|
3818
|
+
const decodedScheme = unescape(String(scheme));
|
|
3819
|
+
if (!VALID_SCHEME.test(decodedScheme)) {
|
|
3820
|
+
throw new TypeError(MALFORMED_SCHEME_ERROR);
|
|
3821
|
+
}
|
|
3822
|
+
return decodedScheme;
|
|
3823
|
+
}
|
|
3630
3824
|
function normalize(uri, options) {
|
|
3631
3825
|
if (typeof uri === "string") {
|
|
3632
3826
|
uri = /** @type {T} */
|
|
@@ -3639,7 +3833,34 @@ var require_fast_uri = __commonJS({
|
|
|
3639
3833
|
}
|
|
3640
3834
|
function resolve(baseURI, relativeURI, options) {
|
|
3641
3835
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3642
|
-
const
|
|
3836
|
+
const {
|
|
3837
|
+
parsed: baseParsed,
|
|
3838
|
+
malformedAuthorityOrPort: baseMalformed,
|
|
3839
|
+
malformedPercentEncoding: baseMalformedPercentEncoding,
|
|
3840
|
+
malformedSchemeSpecific: baseMalformedSchemeSpecific,
|
|
3841
|
+
malformedHost: baseMalformedHost,
|
|
3842
|
+
malformedScheme: baseMalformedScheme
|
|
3843
|
+
} = parseWithStatus(baseURI, schemelessOptions);
|
|
3844
|
+
const {
|
|
3845
|
+
parsed: relativeParsed,
|
|
3846
|
+
malformedAuthorityOrPort: relativeMalformed,
|
|
3847
|
+
malformedPercentEncoding: relativeMalformedPercentEncoding,
|
|
3848
|
+
malformedSchemeSpecific: relativeMalformedSchemeSpecific,
|
|
3849
|
+
malformedHost: relativeMalformedHost,
|
|
3850
|
+
malformedScheme: relativeMalformedScheme
|
|
3851
|
+
} = parseWithStatus(relativeURI, schemelessOptions);
|
|
3852
|
+
if (baseMalformed || relativeMalformed || baseMalformedPercentEncoding || relativeMalformedPercentEncoding || baseMalformedSchemeSpecific || relativeMalformedSchemeSpecific || baseMalformedHost || relativeMalformedHost || baseMalformedScheme || relativeMalformedScheme) {
|
|
3853
|
+
throw new Error(baseParsed.error || relativeParsed.error || "URI is malformed.");
|
|
3854
|
+
}
|
|
3855
|
+
const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
|
|
3856
|
+
const resolvedSchemeHandler = getSchemeHandler(options && options.scheme || resolved.scheme);
|
|
3857
|
+
const resolvedHost = resolved.host;
|
|
3858
|
+
const resolvedHostIsIP = resolvedHost !== void 0 && resolvedHost !== "" && (isIPv4(resolvedHost) || normalizeIPv6(resolvedHost).isIPV6);
|
|
3859
|
+
canonicalizeHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP);
|
|
3860
|
+
const encodedASCIIHost = resolvedHost && resolvedHost.indexOf("%") !== -1 && !/\P{ASCII}/u.test(resolvedHost);
|
|
3861
|
+
if (resolved.error && !encodedASCIIHost) {
|
|
3862
|
+
throw new Error(resolved.error);
|
|
3863
|
+
}
|
|
3643
3864
|
schemelessOptions.skipEscape = true;
|
|
3644
3865
|
return serialize(resolved, schemelessOptions);
|
|
3645
3866
|
}
|
|
@@ -3699,7 +3920,7 @@ var require_fast_uri = __commonJS({
|
|
|
3699
3920
|
function equal(uriA, uriB, options) {
|
|
3700
3921
|
const normalizedA = normalizeComparableURI(uriA, options);
|
|
3701
3922
|
const normalizedB = normalizeComparableURI(uriB, options);
|
|
3702
|
-
return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA
|
|
3923
|
+
return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA === normalizedB;
|
|
3703
3924
|
}
|
|
3704
3925
|
function serialize(cmpts, opts) {
|
|
3705
3926
|
const component = {
|
|
@@ -3720,19 +3941,22 @@ var require_fast_uri = __commonJS({
|
|
|
3720
3941
|
};
|
|
3721
3942
|
const options = Object.assign({}, opts);
|
|
3722
3943
|
const uriTokens = [];
|
|
3944
|
+
if (component.scheme) {
|
|
3945
|
+
component.scheme = decodeValidScheme(component.scheme);
|
|
3946
|
+
}
|
|
3723
3947
|
const schemeHandler = getSchemeHandler(options.scheme || component.scheme);
|
|
3724
3948
|
if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
|
|
3949
|
+
const hasAuthority = component.userinfo !== void 0 || component.host !== void 0 || component.port !== void 0;
|
|
3950
|
+
const pathNoScheme = !options.skipEscape && component.scheme === void 0 && !hasAuthority;
|
|
3725
3951
|
if (component.path !== void 0) {
|
|
3726
3952
|
if (!options.skipEscape) {
|
|
3727
|
-
component.path =
|
|
3728
|
-
if (component.scheme !== void 0) {
|
|
3729
|
-
component.path = component.path.split("%3A").join(":");
|
|
3730
|
-
}
|
|
3953
|
+
component.path = serializePathEncoding(component.path, pathNoScheme);
|
|
3731
3954
|
} else {
|
|
3732
3955
|
component.path = normalizePercentEncoding(component.path);
|
|
3733
3956
|
}
|
|
3734
3957
|
}
|
|
3735
3958
|
if (options.reference !== "suffix" && component.scheme) {
|
|
3959
|
+
component.scheme = decodeValidScheme(component.scheme);
|
|
3736
3960
|
uriTokens.push(component.scheme, ":");
|
|
3737
3961
|
}
|
|
3738
3962
|
const authority = recomposeAuthority(component);
|
|
@@ -3750,21 +3974,25 @@ var require_fast_uri = __commonJS({
|
|
|
3750
3974
|
if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) {
|
|
3751
3975
|
s = removeDotSegments(s);
|
|
3752
3976
|
}
|
|
3977
|
+
if (pathNoScheme) {
|
|
3978
|
+
s = serializePathEncoding(s, true);
|
|
3979
|
+
}
|
|
3753
3980
|
if (authority === void 0 && s[0] === "/" && s[1] === "/") {
|
|
3754
3981
|
s = "/%2F" + s.slice(2);
|
|
3755
3982
|
}
|
|
3756
3983
|
uriTokens.push(s);
|
|
3757
3984
|
}
|
|
3758
3985
|
if (component.query !== void 0) {
|
|
3759
|
-
uriTokens.push("?", component.query);
|
|
3986
|
+
uriTokens.push("?", encodeQuery(component.query));
|
|
3760
3987
|
}
|
|
3761
3988
|
if (component.fragment !== void 0) {
|
|
3762
|
-
uriTokens.push("#", component.fragment);
|
|
3989
|
+
uriTokens.push("#", encodeFragment(component.fragment));
|
|
3763
3990
|
}
|
|
3764
3991
|
return uriTokens.join("");
|
|
3765
3992
|
}
|
|
3766
3993
|
var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
|
|
3767
3994
|
var AUTHORITY_PREFIX = /^(?:[^#/:?]+:)?\/\/([^/?#]*)/;
|
|
3995
|
+
var AUTHORITY_INTRODUCER_REGION = /^(?:[^#/:?]+:)?([/\\\t\n\r]*)/;
|
|
3768
3996
|
function getParseError(parsed, matches) {
|
|
3769
3997
|
if (matches[2] !== void 0 && parsed.path && parsed.path[0] !== "/") {
|
|
3770
3998
|
return 'URI path must start with "/" when authority is present.';
|
|
@@ -3774,6 +4002,32 @@ var require_fast_uri = __commonJS({
|
|
|
3774
4002
|
}
|
|
3775
4003
|
return void 0;
|
|
3776
4004
|
}
|
|
4005
|
+
function hasMalformedPercentEncoding(component) {
|
|
4006
|
+
if (component === void 0) return false;
|
|
4007
|
+
let percent = component.indexOf("%");
|
|
4008
|
+
while (percent !== -1) {
|
|
4009
|
+
if (percent + 2 >= component.length || !/^[\da-f]{2}$/iu.test(component.slice(percent + 1, percent + 3))) {
|
|
4010
|
+
return true;
|
|
4011
|
+
}
|
|
4012
|
+
percent = component.indexOf("%", percent + 3);
|
|
4013
|
+
}
|
|
4014
|
+
return false;
|
|
4015
|
+
}
|
|
4016
|
+
function hasMalformedComponentPercentEncoding(matches) {
|
|
4017
|
+
const host = matches[4];
|
|
4018
|
+
return hasMalformedPercentEncoding(matches[3]) || host !== void 0 && !(host[0] === "[" && host[host.length - 1] === "]") && hasMalformedPercentEncoding(host) || hasMalformedPercentEncoding(matches[6]) || hasMalformedPercentEncoding(matches[7]) || hasMalformedPercentEncoding(matches[8]);
|
|
4019
|
+
}
|
|
4020
|
+
function canonicalizeHost(parsed, options, schemeHandler, isIP) {
|
|
4021
|
+
if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && parsed.host[0] !== "[" && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
|
|
4022
|
+
try {
|
|
4023
|
+
parsed.host = new URL("http://" + parsed.host).hostname;
|
|
4024
|
+
} catch (e) {
|
|
4025
|
+
parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
|
|
4026
|
+
return true;
|
|
4027
|
+
}
|
|
4028
|
+
}
|
|
4029
|
+
return false;
|
|
4030
|
+
}
|
|
3777
4031
|
function parseWithStatus(uri, opts) {
|
|
3778
4032
|
const options = Object.assign({}, opts);
|
|
3779
4033
|
const parsed = {
|
|
@@ -3786,6 +4040,11 @@ var require_fast_uri = __commonJS({
|
|
|
3786
4040
|
fragment: void 0
|
|
3787
4041
|
};
|
|
3788
4042
|
let malformedAuthorityOrPort = false;
|
|
4043
|
+
let malformedPercentEncoding = false;
|
|
4044
|
+
let malformedSchemeSpecific = false;
|
|
4045
|
+
let malformedHost = false;
|
|
4046
|
+
let malformedIPLiteral = false;
|
|
4047
|
+
let malformedScheme = false;
|
|
3789
4048
|
let isIP = false;
|
|
3790
4049
|
if (options.reference === "suffix") {
|
|
3791
4050
|
if (options.scheme) {
|
|
@@ -3799,6 +4058,20 @@ var require_fast_uri = __commonJS({
|
|
|
3799
4058
|
parsed.error = "URI authority must not contain a literal backslash.";
|
|
3800
4059
|
malformedAuthorityOrPort = true;
|
|
3801
4060
|
}
|
|
4061
|
+
const introducerMatch = uri.match(AUTHORITY_INTRODUCER_REGION);
|
|
4062
|
+
if (introducerMatch !== null) {
|
|
4063
|
+
const region = introducerMatch[1];
|
|
4064
|
+
const normalizedRegion = region.replace(/[\t\n\r]/g, "");
|
|
4065
|
+
if (normalizedRegion.length >= 2) {
|
|
4066
|
+
if (normalizedRegion.slice(0, 2) !== "//") {
|
|
4067
|
+
parsed.error = parsed.error || "URI authority must not contain a literal backslash.";
|
|
4068
|
+
malformedAuthorityOrPort = true;
|
|
4069
|
+
} else if (region.length !== normalizedRegion.length) {
|
|
4070
|
+
parsed.error = parsed.error || "URI authority introducer must not contain whitespace.";
|
|
4071
|
+
malformedAuthorityOrPort = true;
|
|
4072
|
+
}
|
|
4073
|
+
}
|
|
4074
|
+
}
|
|
3802
4075
|
const matches = uri.match(URI_PARSE);
|
|
3803
4076
|
if (matches) {
|
|
3804
4077
|
parsed.scheme = matches[1];
|
|
@@ -3808,6 +4081,19 @@ var require_fast_uri = __commonJS({
|
|
|
3808
4081
|
parsed.path = matches[6] || "";
|
|
3809
4082
|
parsed.query = matches[7];
|
|
3810
4083
|
parsed.fragment = matches[8];
|
|
4084
|
+
if (parsed.scheme !== void 0) {
|
|
4085
|
+
const decodedScheme = unescape(parsed.scheme);
|
|
4086
|
+
if (VALID_SCHEME.test(decodedScheme)) {
|
|
4087
|
+
parsed.scheme = decodedScheme.toLowerCase();
|
|
4088
|
+
} else {
|
|
4089
|
+
parsed.error = parsed.error || MALFORMED_SCHEME_ERROR;
|
|
4090
|
+
malformedScheme = true;
|
|
4091
|
+
}
|
|
4092
|
+
}
|
|
4093
|
+
malformedPercentEncoding = hasMalformedComponentPercentEncoding(matches);
|
|
4094
|
+
if (malformedPercentEncoding) {
|
|
4095
|
+
parsed.error = parsed.error || "URI contains malformed percent-encoding.";
|
|
4096
|
+
}
|
|
3811
4097
|
if (isNaN(parsed.port)) {
|
|
3812
4098
|
parsed.port = matches[5];
|
|
3813
4099
|
}
|
|
@@ -3819,9 +4105,15 @@ var require_fast_uri = __commonJS({
|
|
|
3819
4105
|
if (parsed.host) {
|
|
3820
4106
|
const ipv4result = isIPv4(parsed.host);
|
|
3821
4107
|
if (ipv4result === false) {
|
|
4108
|
+
const bracketedIPLiteral = parsed.host[0] === "[" && parsed.host[parsed.host.length - 1] === "]";
|
|
3822
4109
|
const ipv6result = normalizeIPv6(parsed.host);
|
|
3823
|
-
|
|
3824
|
-
|
|
4110
|
+
isIP = ipv6result.isIPV6 || ipv6result.isIPVFuture === true;
|
|
4111
|
+
malformedIPLiteral = bracketedIPLiteral && ipv6result.error === true;
|
|
4112
|
+
parsed.host = isIP ? ipv6result.host : ipv6result.host.toLowerCase();
|
|
4113
|
+
if (malformedIPLiteral) {
|
|
4114
|
+
parsed.error = parsed.error || "URI host is malformed.";
|
|
4115
|
+
malformedAuthorityOrPort = true;
|
|
4116
|
+
}
|
|
3825
4117
|
} else {
|
|
3826
4118
|
isIP = true;
|
|
3827
4119
|
}
|
|
@@ -3839,42 +4131,34 @@ var require_fast_uri = __commonJS({
|
|
|
3839
4131
|
parsed.error = parsed.error || "URI is not a " + options.reference + " reference.";
|
|
3840
4132
|
}
|
|
3841
4133
|
const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme);
|
|
3842
|
-
|
|
3843
|
-
if (parsed.host && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
|
|
3844
|
-
try {
|
|
3845
|
-
parsed.host = new URL("http://" + parsed.host).hostname;
|
|
3846
|
-
} catch (e) {
|
|
3847
|
-
parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
|
|
3848
|
-
}
|
|
3849
|
-
}
|
|
3850
|
-
}
|
|
4134
|
+
malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP);
|
|
3851
4135
|
if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
|
|
3852
4136
|
if (uri.indexOf("%") !== -1) {
|
|
3853
|
-
if (parsed.
|
|
3854
|
-
parsed.
|
|
3855
|
-
|
|
3856
|
-
if (parsed.host !== void 0) {
|
|
3857
|
-
parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP);
|
|
4137
|
+
if (parsed.host !== void 0 && !malformedIPLiteral) {
|
|
4138
|
+
const host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
|
|
4139
|
+
parsed.host = reescapeHostDelimiters(host, isIP);
|
|
3858
4140
|
}
|
|
3859
4141
|
}
|
|
3860
4142
|
if (parsed.path) {
|
|
3861
4143
|
parsed.path = normalizePathEncoding(parsed.path);
|
|
3862
4144
|
}
|
|
4145
|
+
if (parsed.query) {
|
|
4146
|
+
parsed.query = normalizeQueryFragmentEncoding(parsed.query);
|
|
4147
|
+
}
|
|
3863
4148
|
if (parsed.fragment) {
|
|
3864
|
-
|
|
3865
|
-
parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
|
|
3866
|
-
} catch {
|
|
3867
|
-
parsed.error = parsed.error || "URI malformed";
|
|
3868
|
-
}
|
|
4149
|
+
parsed.fragment = normalizeQueryFragmentEncoding(parsed.fragment);
|
|
3869
4150
|
}
|
|
3870
4151
|
}
|
|
3871
4152
|
if (schemeHandler && schemeHandler.parse) {
|
|
3872
4153
|
schemeHandler.parse(parsed, options);
|
|
4154
|
+
if (schemeHandler === SCHEMES.urn && parsed.nid === void 0) {
|
|
4155
|
+
malformedSchemeSpecific = true;
|
|
4156
|
+
}
|
|
3873
4157
|
}
|
|
3874
4158
|
} else {
|
|
3875
4159
|
parsed.error = parsed.error || "URI can not be parsed.";
|
|
3876
4160
|
}
|
|
3877
|
-
return { parsed, malformedAuthorityOrPort };
|
|
4161
|
+
return { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme };
|
|
3878
4162
|
}
|
|
3879
4163
|
function parse3(uri, opts) {
|
|
3880
4164
|
return parseWithStatus(uri, opts).parsed;
|
|
@@ -3883,20 +4167,28 @@ var require_fast_uri = __commonJS({
|
|
|
3883
4167
|
return normalizeStringWithStatus(uri, opts).normalized;
|
|
3884
4168
|
}
|
|
3885
4169
|
function normalizeStringWithStatus(uri, opts) {
|
|
3886
|
-
const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts);
|
|
4170
|
+
const { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = parseWithStatus(uri, opts);
|
|
3887
4171
|
return {
|
|
3888
|
-
normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
|
|
3889
|
-
malformedAuthorityOrPort
|
|
4172
|
+
normalized: malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? uri : serialize(parsed, opts),
|
|
4173
|
+
malformedAuthorityOrPort,
|
|
4174
|
+
malformedPercentEncoding,
|
|
4175
|
+
malformedSchemeSpecific,
|
|
4176
|
+
malformedHost,
|
|
4177
|
+
malformedScheme
|
|
3890
4178
|
};
|
|
3891
4179
|
}
|
|
3892
4180
|
function normalizeComparableURI(uri, opts) {
|
|
3893
|
-
if (typeof uri
|
|
3894
|
-
|
|
3895
|
-
return malformedAuthorityOrPort ? void 0 : normalized;
|
|
4181
|
+
if (typeof uri !== "string" && typeof uri !== "object") {
|
|
4182
|
+
return void 0;
|
|
3896
4183
|
}
|
|
3897
|
-
|
|
3898
|
-
|
|
4184
|
+
let value;
|
|
4185
|
+
try {
|
|
4186
|
+
value = typeof uri === "string" ? uri : serialize(uri, opts);
|
|
4187
|
+
} catch {
|
|
4188
|
+
return void 0;
|
|
3899
4189
|
}
|
|
4190
|
+
const { normalized, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = normalizeStringWithStatus(value, opts);
|
|
4191
|
+
return malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? void 0 : normalized;
|
|
3900
4192
|
}
|
|
3901
4193
|
var fastUri = {
|
|
3902
4194
|
SCHEMES,
|
package/hooks/hooks.json
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
],
|
|
27
27
|
"PostToolUse": [
|
|
28
28
|
{
|
|
29
|
-
"matcher": "choose_identity|create_identity|create_root_identity",
|
|
29
|
+
"matcher": "choose_identity|create_identity|create_root_identity|create_temporary_identity",
|
|
30
30
|
"hooks": [
|
|
31
31
|
{
|
|
32
32
|
"type": "command",
|
|
@@ -35,6 +35,18 @@
|
|
|
35
35
|
}
|
|
36
36
|
]
|
|
37
37
|
}
|
|
38
|
+
],
|
|
39
|
+
"SessionEnd": [
|
|
40
|
+
{
|
|
41
|
+
"hooks": [
|
|
42
|
+
{
|
|
43
|
+
"type": "command",
|
|
44
|
+
"command": "exec node \"${PLUGIN_ROOT}/bin/proxy.mjs\" session-end",
|
|
45
|
+
"timeout": 30,
|
|
46
|
+
"statusMessage": "Closing temporary ours identities"
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
38
50
|
]
|
|
39
51
|
}
|
|
40
52
|
}
|
package/install.sh
CHANGED
|
@@ -32,9 +32,14 @@ ensure_daemon_latest(){
|
|
|
32
32
|
npm i -g @ours.network/cli@latest @ours.network/mcp@latest
|
|
33
33
|
after="$(ours version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)"
|
|
34
34
|
if ! ours daemon status >/dev/null 2>&1; then
|
|
35
|
-
say "starting the ours daemon…"
|
|
35
|
+
say "starting the ours daemon…"
|
|
36
|
+
if ! ours daemon start; then say "could not start the ours daemon; installation stopped."; return 1; fi
|
|
36
37
|
elif [ -n "$before" ] && [ "$before" != "$after" ]; then
|
|
37
|
-
say "operator CLI upgraded (v${before} → v${after}) — restarting its daemon…"
|
|
38
|
+
say "operator CLI upgraded (v${before} → v${after}) — restarting its daemon…"
|
|
39
|
+
if ! ours daemon restart; then
|
|
40
|
+
say "restart failed; trying a clean start…"
|
|
41
|
+
if ! ours daemon start; then say "could not restart or start the upgraded daemon; installation stopped."; return 1; fi
|
|
42
|
+
fi
|
|
38
43
|
else
|
|
39
44
|
say "daemon already current (v${after:-unknown})."
|
|
40
45
|
fi
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ours.network/codex",
|
|
3
|
-
"version": "0.18.0-nightly.
|
|
3
|
+
"version": "0.18.0-nightly.6",
|
|
4
4
|
"description": "Native Codex plugin for secure ours.network messaging and explicitly armed, session-scoped live mail wake.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "FSL-1.1-Apache-2.0",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
49
|
-
"@ours.network/mcp": "0.18.0-nightly.
|
|
50
|
-
"@ours.network/sdk": "3.
|
|
49
|
+
"@ours.network/mcp": "0.18.0-nightly.6",
|
|
50
|
+
"@ours.network/sdk": "3.2.2",
|
|
51
51
|
"ws": "^8.21.0",
|
|
52
52
|
"zod": "^3.25.76"
|
|
53
53
|
},
|
package/skills/ours/SKILL.md
CHANGED
|
@@ -64,15 +64,15 @@ Walk the user through it, explaining as you go:
|
|
|
64
64
|
every one is automatically associated with the Human identity, and its invites carry
|
|
65
65
|
the verified "agent X of person Y" chain.
|
|
66
66
|
|
|
67
|
-
**Do not create an agent identity on a host with no Human identity.**
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
**Do not create an agent identity on a host with no Human identity.** Older servers may
|
|
68
|
+
accept that as unassociated legacy state: no verified human behind it in invites, no
|
|
69
|
+
control plane. This skill never creates or exposes such state.
|
|
70
70
|
|
|
71
71
|
| Tempting shortcut | Why it's wrong |
|
|
72
72
|
|---|---|
|
|
73
73
|
| "The user clearly asked for an *agent*, so the human question doesn't apply" | The gate is about ORDER, not classification. Create the Human identity first, then the agent they asked for. |
|
|
74
74
|
| "The user is busy / gave me everything I need for the agent" | Onboarding adds one question — the person's name. Ask it. |
|
|
75
|
-
| "`create_identity` works fine without a Human identity" |
|
|
75
|
+
| "`create_identity` works fine without a Human identity" | Older servers may create unassociated legacy state with no human association. Never do it. |
|
|
76
76
|
| "I'll create the agent now and the Human identity later" | Later never comes, and the agent's invites go out with no human chain. Human first. |
|
|
77
77
|
|
|
78
78
|
## Setup — "set up ours" / "set up the plugin"
|
|
@@ -229,7 +229,8 @@ the bio, so a persona prompt is only needed if they want to role-play it).
|
|
|
229
229
|
|
|
230
230
|
For scratch/one-off work ("make a temporary identity", "throwaway identity"):
|
|
231
231
|
`create_temporary_identity({ name? , bio?, expose_local? })` — name optional (omitted → a
|
|
232
|
-
random public-safe `tmp-…` name),
|
|
232
|
+
random public-safe `tmp-…` name), requires an existing Human identity, creates an
|
|
233
|
+
ephemeral delegated role under it, binds it to this session, and marks it **temporary**:
|
|
233
234
|
|
|
234
235
|
- **Session-scoped local lifetime.** When this session ends — an explicit
|
|
235
236
|
`close_temporary_identity()`, releasing the connection, or the client process dying —
|
|
@@ -241,8 +242,9 @@ random public-safe `tmp-…` name), binds it to this session, and marks it **tem
|
|
|
241
242
|
owning session lives — not even with `force`. A **stale** one (owner process dead) is
|
|
242
243
|
reclaimed automatically by the daemon, or immediately via
|
|
243
244
|
`close_temporary_identity({ name })` from any session.
|
|
244
|
-
-
|
|
245
|
-
|
|
245
|
+
- Its verified Human/root delegation is part of creation; the tool fails closed rather
|
|
246
|
+
than creating unassociated state. It is NOT in the local contact book unless
|
|
247
|
+
`expose_local: true`.
|
|
246
248
|
- `list_identities()` tags each temporary identity with its lease state (owned by this
|
|
247
249
|
session / another live session / stale / closing).
|
|
248
250
|
|
package/src/hooks/runner.mjs
CHANGED
|
@@ -62,7 +62,7 @@ export async function handleHook(payload, { env = process.env, fetch: fetchImpl
|
|
|
62
62
|
if (event === 'SessionStart' && payload.source === 'compact') return { continue: true };
|
|
63
63
|
if (event === 'PostToolUse') {
|
|
64
64
|
if (!socket || !capability || payload.tool_response?.isError) return { continue: true };
|
|
65
|
-
if (!/(choose_identity|create_identity|create_root_identity)$/.test(payload.tool_name || '')) return { continue: true };
|
|
65
|
+
if (!/(choose_identity|create_identity|create_root_identity|create_temporary_identity)$/.test(payload.tool_name || '')) return { continue: true };
|
|
66
66
|
const identity = payload.tool_input?.name;
|
|
67
67
|
if (typeof identity !== 'string' || !identity.trim()) return { continue: true };
|
|
68
68
|
await send(socket, capability, { command: 'binding_changed', identity });
|
package/src/launcher.mjs
CHANGED
|
@@ -2,7 +2,8 @@ import { spawn as nodeSpawn } from 'node:child_process';
|
|
|
2
2
|
import { createServer } from 'node:net';
|
|
3
3
|
import { chmod, mkdtemp, rm } from 'node:fs/promises';
|
|
4
4
|
import { tmpdir } from 'node:os';
|
|
5
|
-
import { join } from 'node:path';
|
|
5
|
+
import { dirname, join } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
6
7
|
import { randomBytes } from 'node:crypto';
|
|
7
8
|
import { once } from 'node:events';
|
|
8
9
|
import { resolveDaemonProfile } from './profile.mjs';
|
|
@@ -28,6 +29,10 @@ export function launcherEnvironment(env, profile, control) {
|
|
|
28
29
|
OURS_CODEX_CONTROL_SOCKET: control.socketPath,
|
|
29
30
|
OURS_CODEX_CAPABILITY: control.capability,
|
|
30
31
|
OURS_CODEX_LIVE: '1',
|
|
32
|
+
// One stable owner pid for the MCP proxy, hooks, and launcher's own cleanup
|
|
33
|
+
// call. The bin shim preserves an explicit value instead of replacing it
|
|
34
|
+
// with whichever child happened to spawn it.
|
|
35
|
+
OURS_CLIENT_PID: String(process.pid),
|
|
31
36
|
};
|
|
32
37
|
if (profile.token) out.OURS_API_TOKEN = profile.token;
|
|
33
38
|
else delete out.OURS_API_TOKEN;
|
|
@@ -89,10 +94,24 @@ export async function runLauncher({
|
|
|
89
94
|
let client;
|
|
90
95
|
let control;
|
|
91
96
|
let watcher;
|
|
97
|
+
const sessionEndShim = join(dirname(dirname(fileURLToPath(import.meta.url))), 'bin', 'proxy.mjs');
|
|
92
98
|
const cleanup = async () => {
|
|
93
99
|
watcher?.stop();
|
|
94
100
|
await control?.close().catch(() => {});
|
|
95
101
|
client?.close();
|
|
102
|
+
// The TUI exit is an authoritative normal session end. Run the same lease
|
|
103
|
+
// DELETE seam as the native hook while the shared daemon is still reachable;
|
|
104
|
+
// duplicate hook+launcher cleanup is intentionally idempotent.
|
|
105
|
+
const end = spawn(process.execPath, [sessionEndShim, 'session-end'], {
|
|
106
|
+
env: processEnvs.appServer,
|
|
107
|
+
stdio: 'ignore',
|
|
108
|
+
});
|
|
109
|
+
end.once('error', () => {});
|
|
110
|
+
await Promise.race([
|
|
111
|
+
waitExit(end),
|
|
112
|
+
new Promise((resolve) => setTimeout(resolve, 30_000)),
|
|
113
|
+
]).catch(() => {});
|
|
114
|
+
if (end.exitCode == null) end.kill('SIGTERM');
|
|
96
115
|
if (tui && tui.exitCode == null) tui.kill('SIGTERM');
|
|
97
116
|
if (appServer && appServer.exitCode == null) appServer.kill('SIGTERM');
|
|
98
117
|
await rm(runtimeDir, { recursive: true, force: true });
|