@themoltnet/legreffier 0.9.0 → 0.10.0

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.
Files changed (3) hide show
  1. package/README.md +3 -4
  2. package/dist/index.js +945 -82
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -299,11 +299,10 @@ Then just `pnpm codex`.
299
299
 
300
300
  ## Activation
301
301
 
302
- Once inside a Claude Code or Codex session:
302
+ Once inside a coding session, activate the skill:
303
303
 
304
- ```
305
- /legreffier
306
- ```
304
+ - **Claude Code**: `/legreffier`
305
+ - **Codex**: `$legreffier`
307
306
 
308
307
  This sets `GIT_CONFIG_GLOBAL` to the agent's gitconfig, verifies the signing
309
308
  key, and confirms readiness. All subsequent git commits use the agent identity.
package/dist/index.js CHANGED
@@ -6,9 +6,9 @@ import { execFileSync } from "node:child_process";
6
6
  import { join } from "node:path";
7
7
  import { useState, useEffect, useReducer, useRef } from "react";
8
8
  import figlet from "figlet";
9
+ import { createHash, randomBytes as randomBytes$2 } from "crypto";
9
10
  import { readFile, writeFile, mkdir, chmod, rm } from "node:fs/promises";
10
11
  import { homedir } from "node:os";
11
- import { createHash, randomBytes as randomBytes$2 } from "crypto";
12
12
  import { parse, stringify } from "smol-toml";
13
13
  import open from "open";
14
14
  const MOLTNET_GITCONFIG_RE = /\.moltnet\/([^/]+)\/gitconfig$/;
@@ -2183,15 +2183,15 @@ let wNAF$1 = class wNAF {
2183
2183
  const { windows, windowSize } = calcWOpts(W2, this.bits);
2184
2184
  const points = [];
2185
2185
  let p = point;
2186
- let base = p;
2186
+ let base2 = p;
2187
2187
  for (let window = 0; window < windows; window++) {
2188
- base = p;
2189
- points.push(base);
2188
+ base2 = p;
2189
+ points.push(base2);
2190
2190
  for (let i = 1; i < windowSize; i++) {
2191
- base = base.add(p);
2192
- points.push(base);
2191
+ base2 = base2.add(p);
2192
+ points.push(base2);
2193
2193
  }
2194
- p = base.double();
2194
+ p = base2.double();
2195
2195
  }
2196
2196
  return points;
2197
2197
  }
@@ -4076,87 +4076,399 @@ const createClient = (config = {}) => {
4076
4076
  createClient(
4077
4077
  createConfig({ baseUrl: "https://api.themolt.net" })
4078
4078
  );
4079
- class MoltNetError extends Error {
4080
- constructor(message, options) {
4081
- super(message);
4082
- __publicField(this, "code");
4083
- __publicField(this, "statusCode");
4084
- __publicField(this, "detail");
4085
- this.name = "MoltNetError";
4086
- this.code = options.code;
4087
- this.statusCode = options.statusCode;
4088
- this.detail = options.detail;
4079
+ function coerce$1(o) {
4080
+ if (o instanceof Uint8Array && o.constructor.name === "Uint8Array") {
4081
+ return o;
4089
4082
  }
4083
+ if (o instanceof ArrayBuffer) {
4084
+ return new Uint8Array(o);
4085
+ }
4086
+ if (ArrayBuffer.isView(o)) {
4087
+ return new Uint8Array(o.buffer, o.byteOffset, o.byteLength);
4088
+ }
4089
+ throw new Error("Unknown type, must be binary type");
4090
4090
  }
4091
- function problemToError(problem, statusCode) {
4092
- return new MoltNetError(problem.title ?? "Request failed", {
4093
- code: problem.type ?? problem.code ?? "UNKNOWN",
4094
- statusCode,
4095
- detail: problem.detail
4096
- });
4097
- }
4098
- async function writeMcpConfig(mcpConfig, dir2) {
4099
- const targetDir = dir2 ?? process.cwd();
4100
- const filePath = join(targetDir, ".mcp.json");
4101
- let existing = {};
4102
- try {
4103
- const content = await readFile(filePath, "utf-8");
4104
- existing = JSON.parse(content);
4105
- } catch {
4091
+ function base$1(ALPHABET, name2) {
4092
+ if (ALPHABET.length >= 255) {
4093
+ throw new TypeError("Alphabet too long");
4106
4094
  }
4107
- const merged = {
4108
- ...existing,
4109
- mcpServers: {
4110
- ...existing.mcpServers ?? {},
4111
- ...mcpConfig.mcpServers
4095
+ var BASE_MAP = new Uint8Array(256);
4096
+ for (var j = 0; j < BASE_MAP.length; j++) {
4097
+ BASE_MAP[j] = 255;
4098
+ }
4099
+ for (var i = 0; i < ALPHABET.length; i++) {
4100
+ var x = ALPHABET.charAt(i);
4101
+ var xc = x.charCodeAt(0);
4102
+ if (BASE_MAP[xc] !== 255) {
4103
+ throw new TypeError(x + " is ambiguous");
4104
+ }
4105
+ BASE_MAP[xc] = i;
4106
+ }
4107
+ var BASE = ALPHABET.length;
4108
+ var LEADER = ALPHABET.charAt(0);
4109
+ var FACTOR = Math.log(BASE) / Math.log(256);
4110
+ var iFACTOR = Math.log(256) / Math.log(BASE);
4111
+ function encode2(source) {
4112
+ if (source instanceof Uint8Array)
4113
+ ;
4114
+ else if (ArrayBuffer.isView(source)) {
4115
+ source = new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
4116
+ } else if (Array.isArray(source)) {
4117
+ source = Uint8Array.from(source);
4118
+ }
4119
+ if (!(source instanceof Uint8Array)) {
4120
+ throw new TypeError("Expected Uint8Array");
4121
+ }
4122
+ if (source.length === 0) {
4123
+ return "";
4124
+ }
4125
+ var zeroes = 0;
4126
+ var length2 = 0;
4127
+ var pbegin = 0;
4128
+ var pend = source.length;
4129
+ while (pbegin !== pend && source[pbegin] === 0) {
4130
+ pbegin++;
4131
+ zeroes++;
4132
+ }
4133
+ var size = (pend - pbegin) * iFACTOR + 1 >>> 0;
4134
+ var b58 = new Uint8Array(size);
4135
+ while (pbegin !== pend) {
4136
+ var carry = source[pbegin];
4137
+ var i2 = 0;
4138
+ for (var it1 = size - 1; (carry !== 0 || i2 < length2) && it1 !== -1; it1--, i2++) {
4139
+ carry += 256 * b58[it1] >>> 0;
4140
+ b58[it1] = carry % BASE >>> 0;
4141
+ carry = carry / BASE >>> 0;
4142
+ }
4143
+ if (carry !== 0) {
4144
+ throw new Error("Non-zero carry");
4145
+ }
4146
+ length2 = i2;
4147
+ pbegin++;
4112
4148
  }
4149
+ var it2 = size - length2;
4150
+ while (it2 !== size && b58[it2] === 0) {
4151
+ it2++;
4152
+ }
4153
+ var str = LEADER.repeat(zeroes);
4154
+ for (; it2 < size; ++it2) {
4155
+ str += ALPHABET.charAt(b58[it2]);
4156
+ }
4157
+ return str;
4158
+ }
4159
+ function decodeUnsafe(source) {
4160
+ if (typeof source !== "string") {
4161
+ throw new TypeError("Expected String");
4162
+ }
4163
+ if (source.length === 0) {
4164
+ return new Uint8Array();
4165
+ }
4166
+ var psz = 0;
4167
+ if (source[psz] === " ") {
4168
+ return;
4169
+ }
4170
+ var zeroes = 0;
4171
+ var length2 = 0;
4172
+ while (source[psz] === LEADER) {
4173
+ zeroes++;
4174
+ psz++;
4175
+ }
4176
+ var size = (source.length - psz) * FACTOR + 1 >>> 0;
4177
+ var b256 = new Uint8Array(size);
4178
+ while (source[psz]) {
4179
+ var carry = BASE_MAP[source.charCodeAt(psz)];
4180
+ if (carry === 255) {
4181
+ return;
4182
+ }
4183
+ var i2 = 0;
4184
+ for (var it3 = size - 1; (carry !== 0 || i2 < length2) && it3 !== -1; it3--, i2++) {
4185
+ carry += BASE * b256[it3] >>> 0;
4186
+ b256[it3] = carry % 256 >>> 0;
4187
+ carry = carry / 256 >>> 0;
4188
+ }
4189
+ if (carry !== 0) {
4190
+ throw new Error("Non-zero carry");
4191
+ }
4192
+ length2 = i2;
4193
+ psz++;
4194
+ }
4195
+ if (source[psz] === " ") {
4196
+ return;
4197
+ }
4198
+ var it4 = size - length2;
4199
+ while (it4 !== size && b256[it4] === 0) {
4200
+ it4++;
4201
+ }
4202
+ var vch = new Uint8Array(zeroes + (size - it4));
4203
+ var j2 = zeroes;
4204
+ while (it4 !== size) {
4205
+ vch[j2++] = b256[it4++];
4206
+ }
4207
+ return vch;
4208
+ }
4209
+ function decode2(string) {
4210
+ var buffer = decodeUnsafe(string);
4211
+ if (buffer) {
4212
+ return buffer;
4213
+ }
4214
+ throw new Error(`Non-${name2} character`);
4215
+ }
4216
+ return {
4217
+ encode: encode2,
4218
+ decodeUnsafe,
4219
+ decode: decode2
4113
4220
  };
4114
- await writeFile(filePath, JSON.stringify(merged, null, 2) + "\n");
4115
- return filePath;
4116
- }
4117
- function getConfigDir() {
4118
- return join(homedir(), ".config", "moltnet");
4119
- }
4120
- function getConfigPath(configDir) {
4121
- return join(configDir ?? getConfigDir(), "moltnet.json");
4122
4221
  }
4123
- async function readConfig(configDir) {
4124
- const dir2 = configDir ?? getConfigDir();
4125
- try {
4126
- const content = await readFile(join(dir2, "moltnet.json"), "utf-8");
4127
- return JSON.parse(content);
4128
- } catch {
4222
+ var src$1 = base$1;
4223
+ var _brrp__multiformats_scope_baseX$1 = src$1;
4224
+ let Encoder$1 = class Encoder {
4225
+ constructor(name2, prefix, baseEncode) {
4226
+ __publicField(this, "name");
4227
+ __publicField(this, "prefix");
4228
+ __publicField(this, "baseEncode");
4229
+ this.name = name2;
4230
+ this.prefix = prefix;
4231
+ this.baseEncode = baseEncode;
4232
+ }
4233
+ encode(bytes) {
4234
+ if (bytes instanceof Uint8Array) {
4235
+ return `${this.prefix}${this.baseEncode(bytes)}`;
4236
+ } else {
4237
+ throw Error("Unknown type, must be binary type");
4238
+ }
4129
4239
  }
4130
- try {
4131
- const content = await readFile(join(dir2, "credentials.json"), "utf-8");
4132
- console.warn(
4133
- "Warning: credentials.json is deprecated. New writes use moltnet.json. Support will be removed in 3 minor versions."
4134
- );
4135
- return JSON.parse(content);
4136
- } catch {
4137
- return null;
4240
+ };
4241
+ let Decoder$1 = class Decoder {
4242
+ constructor(name2, prefix, baseDecode) {
4243
+ __publicField(this, "name");
4244
+ __publicField(this, "prefix");
4245
+ __publicField(this, "baseDecode");
4246
+ __publicField(this, "prefixCodePoint");
4247
+ this.name = name2;
4248
+ this.prefix = prefix;
4249
+ const prefixCodePoint = prefix.codePointAt(0);
4250
+ if (prefixCodePoint === void 0) {
4251
+ throw new Error("Invalid prefix character");
4252
+ }
4253
+ this.prefixCodePoint = prefixCodePoint;
4254
+ this.baseDecode = baseDecode;
4138
4255
  }
4256
+ decode(text) {
4257
+ if (typeof text === "string") {
4258
+ if (text.codePointAt(0) !== this.prefixCodePoint) {
4259
+ throw Error(`Unable to decode multibase string ${JSON.stringify(text)}, ${this.name} decoder only supports inputs prefixed with ${this.prefix}`);
4260
+ }
4261
+ return this.baseDecode(text.slice(this.prefix.length));
4262
+ } else {
4263
+ throw Error("Can only multibase decode strings");
4264
+ }
4265
+ }
4266
+ or(decoder) {
4267
+ return or$1(this, decoder);
4268
+ }
4269
+ };
4270
+ let ComposedDecoder$1 = class ComposedDecoder {
4271
+ constructor(decoders) {
4272
+ __publicField(this, "decoders");
4273
+ this.decoders = decoders;
4274
+ }
4275
+ or(decoder) {
4276
+ return or$1(this, decoder);
4277
+ }
4278
+ decode(input) {
4279
+ const prefix = input[0];
4280
+ const decoder = this.decoders[prefix];
4281
+ if (decoder != null) {
4282
+ return decoder.decode(input);
4283
+ } else {
4284
+ throw RangeError(`Unable to decode multibase string ${JSON.stringify(input)}, only inputs prefixed with ${Object.keys(this.decoders)} are supported`);
4285
+ }
4286
+ }
4287
+ };
4288
+ function or$1(left, right) {
4289
+ return new ComposedDecoder$1({
4290
+ ...left.decoders ?? { [left.prefix]: left },
4291
+ ...right.decoders ?? { [right.prefix]: right }
4292
+ });
4139
4293
  }
4140
- async function writeConfig(config, configDir) {
4141
- const dir2 = configDir ?? getConfigDir();
4142
- await mkdir(dir2, { recursive: true });
4143
- const filePath = join(dir2, "moltnet.json");
4144
- await writeFile(filePath, JSON.stringify(config, null, 2) + "\n", {
4145
- mode: 384
4294
+ let Codec$1 = class Codec {
4295
+ constructor(name2, prefix, baseEncode, baseDecode) {
4296
+ __publicField(this, "name");
4297
+ __publicField(this, "prefix");
4298
+ __publicField(this, "baseEncode");
4299
+ __publicField(this, "baseDecode");
4300
+ __publicField(this, "encoder");
4301
+ __publicField(this, "decoder");
4302
+ this.name = name2;
4303
+ this.prefix = prefix;
4304
+ this.baseEncode = baseEncode;
4305
+ this.baseDecode = baseDecode;
4306
+ this.encoder = new Encoder$1(name2, prefix, baseEncode);
4307
+ this.decoder = new Decoder$1(name2, prefix, baseDecode);
4308
+ }
4309
+ encode(input) {
4310
+ return this.encoder.encode(input);
4311
+ }
4312
+ decode(input) {
4313
+ return this.decoder.decode(input);
4314
+ }
4315
+ };
4316
+ function from$1({ name: name2, prefix, encode: encode2, decode: decode2 }) {
4317
+ return new Codec$1(name2, prefix, encode2, decode2);
4318
+ }
4319
+ function baseX$1({ name: name2, prefix, alphabet }) {
4320
+ const { encode: encode2, decode: decode2 } = _brrp__multiformats_scope_baseX$1(alphabet, name2);
4321
+ return from$1({
4322
+ prefix,
4323
+ name: name2,
4324
+ encode: encode2,
4325
+ decode: (text) => coerce$1(decode2(text))
4146
4326
  });
4147
- await chmod(filePath, 384);
4148
- return filePath;
4149
4327
  }
4150
- async function updateConfigSection(section, data, configDir) {
4151
- const config = await readConfig(configDir);
4152
- if (!config) {
4153
- throw new Error("No config found — run `moltnet register` first");
4328
+ function decode$3(string, alphabetIdx, bitsPerChar, name2) {
4329
+ let end = string.length;
4330
+ while (string[end - 1] === "=") {
4331
+ --end;
4332
+ }
4333
+ const out = new Uint8Array(end * bitsPerChar / 8 | 0);
4334
+ let bits = 0;
4335
+ let buffer = 0;
4336
+ let written = 0;
4337
+ for (let i = 0; i < end; ++i) {
4338
+ const value = alphabetIdx[string[i]];
4339
+ if (value === void 0) {
4340
+ throw new SyntaxError(`Non-${name2} character`);
4341
+ }
4342
+ buffer = buffer << bitsPerChar | value;
4343
+ bits += bitsPerChar;
4344
+ if (bits >= 8) {
4345
+ bits -= 8;
4346
+ out[written++] = 255 & buffer >> bits;
4347
+ }
4154
4348
  }
4155
- const existing = config[section] ?? {};
4156
- const updated = { ...existing, ...data };
4157
- Object.assign(config, { [section]: updated });
4158
- await writeConfig(config, configDir);
4349
+ if (bits >= bitsPerChar || (255 & buffer << 8 - bits) !== 0) {
4350
+ throw new SyntaxError("Unexpected end of data");
4351
+ }
4352
+ return out;
4353
+ }
4354
+ function encode$1(data, alphabet, bitsPerChar) {
4355
+ const pad = alphabet[alphabet.length - 1] === "=";
4356
+ const mask = (1 << bitsPerChar) - 1;
4357
+ let out = "";
4358
+ let bits = 0;
4359
+ let buffer = 0;
4360
+ for (let i = 0; i < data.length; ++i) {
4361
+ buffer = buffer << 8 | data[i];
4362
+ bits += 8;
4363
+ while (bits > bitsPerChar) {
4364
+ bits -= bitsPerChar;
4365
+ out += alphabet[mask & buffer >> bits];
4366
+ }
4367
+ }
4368
+ if (bits !== 0) {
4369
+ out += alphabet[mask & buffer << bitsPerChar - bits];
4370
+ }
4371
+ if (pad) {
4372
+ while ((out.length * bitsPerChar & 7) !== 0) {
4373
+ out += "=";
4374
+ }
4375
+ }
4376
+ return out;
4377
+ }
4378
+ function createAlphabetIdx$1(alphabet) {
4379
+ const alphabetIdx = {};
4380
+ for (let i = 0; i < alphabet.length; ++i) {
4381
+ alphabetIdx[alphabet[i]] = i;
4382
+ }
4383
+ return alphabetIdx;
4159
4384
  }
4385
+ function rfc4648$1({ name: name2, prefix, bitsPerChar, alphabet }) {
4386
+ const alphabetIdx = createAlphabetIdx$1(alphabet);
4387
+ return from$1({
4388
+ prefix,
4389
+ name: name2,
4390
+ encode(input) {
4391
+ return encode$1(input, alphabet, bitsPerChar);
4392
+ },
4393
+ decode(input) {
4394
+ return decode$3(input, alphabetIdx, bitsPerChar, name2);
4395
+ }
4396
+ });
4397
+ }
4398
+ rfc4648$1({
4399
+ prefix: "b",
4400
+ name: "base32",
4401
+ alphabet: "abcdefghijklmnopqrstuvwxyz234567",
4402
+ bitsPerChar: 5
4403
+ });
4404
+ rfc4648$1({
4405
+ prefix: "B",
4406
+ name: "base32upper",
4407
+ alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
4408
+ bitsPerChar: 5
4409
+ });
4410
+ rfc4648$1({
4411
+ prefix: "c",
4412
+ name: "base32pad",
4413
+ alphabet: "abcdefghijklmnopqrstuvwxyz234567=",
4414
+ bitsPerChar: 5
4415
+ });
4416
+ rfc4648$1({
4417
+ prefix: "C",
4418
+ name: "base32padupper",
4419
+ alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=",
4420
+ bitsPerChar: 5
4421
+ });
4422
+ rfc4648$1({
4423
+ prefix: "v",
4424
+ name: "base32hex",
4425
+ alphabet: "0123456789abcdefghijklmnopqrstuv",
4426
+ bitsPerChar: 5
4427
+ });
4428
+ rfc4648$1({
4429
+ prefix: "V",
4430
+ name: "base32hexupper",
4431
+ alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUV",
4432
+ bitsPerChar: 5
4433
+ });
4434
+ rfc4648$1({
4435
+ prefix: "t",
4436
+ name: "base32hexpad",
4437
+ alphabet: "0123456789abcdefghijklmnopqrstuv=",
4438
+ bitsPerChar: 5
4439
+ });
4440
+ rfc4648$1({
4441
+ prefix: "T",
4442
+ name: "base32hexpadupper",
4443
+ alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUV=",
4444
+ bitsPerChar: 5
4445
+ });
4446
+ rfc4648$1({
4447
+ prefix: "h",
4448
+ name: "base32z",
4449
+ alphabet: "ybndrfg8ejkmcpqxot1uwisza345h769",
4450
+ bitsPerChar: 5
4451
+ });
4452
+ baseX$1({
4453
+ prefix: "k",
4454
+ name: "base36",
4455
+ alphabet: "0123456789abcdefghijklmnopqrstuvwxyz"
4456
+ });
4457
+ baseX$1({
4458
+ prefix: "K",
4459
+ name: "base36upper",
4460
+ alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
4461
+ });
4462
+ baseX$1({
4463
+ name: "base58btc",
4464
+ prefix: "z",
4465
+ alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
4466
+ });
4467
+ baseX$1({
4468
+ name: "base58flickr",
4469
+ prefix: "Z",
4470
+ alphabet: "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
4471
+ });
4160
4472
  etc.sha512Sync = (...m) => {
4161
4473
  const hash = createHash("sha512");
4162
4474
  m.forEach((msg) => hash.update(msg));
@@ -4265,6 +4577,87 @@ function toSSHPrivateKey(seedBase64) {
4265
4577
  // trailing newline
4266
4578
  ].join("\n");
4267
4579
  }
4580
+ class MoltNetError extends Error {
4581
+ constructor(message, options) {
4582
+ super(message);
4583
+ __publicField(this, "code");
4584
+ __publicField(this, "statusCode");
4585
+ __publicField(this, "detail");
4586
+ this.name = "MoltNetError";
4587
+ this.code = options.code;
4588
+ this.statusCode = options.statusCode;
4589
+ this.detail = options.detail;
4590
+ }
4591
+ }
4592
+ function problemToError(problem, statusCode) {
4593
+ return new MoltNetError(problem.title ?? "Request failed", {
4594
+ code: problem.type ?? problem.code ?? "UNKNOWN",
4595
+ statusCode,
4596
+ detail: problem.detail
4597
+ });
4598
+ }
4599
+ async function writeMcpConfig(mcpConfig, dir2) {
4600
+ const targetDir = dir2 ?? process.cwd();
4601
+ const filePath = join(targetDir, ".mcp.json");
4602
+ let existing = {};
4603
+ try {
4604
+ const content = await readFile(filePath, "utf-8");
4605
+ existing = JSON.parse(content);
4606
+ } catch {
4607
+ }
4608
+ const merged = {
4609
+ ...existing,
4610
+ mcpServers: {
4611
+ ...existing.mcpServers ?? {},
4612
+ ...mcpConfig.mcpServers
4613
+ }
4614
+ };
4615
+ await writeFile(filePath, JSON.stringify(merged, null, 2) + "\n");
4616
+ return filePath;
4617
+ }
4618
+ function getConfigDir() {
4619
+ return join(homedir(), ".config", "moltnet");
4620
+ }
4621
+ function getConfigPath(configDir) {
4622
+ return join(configDir ?? getConfigDir(), "moltnet.json");
4623
+ }
4624
+ async function readConfig(configDir) {
4625
+ const dir2 = configDir ?? getConfigDir();
4626
+ try {
4627
+ const content = await readFile(join(dir2, "moltnet.json"), "utf-8");
4628
+ return JSON.parse(content);
4629
+ } catch {
4630
+ }
4631
+ try {
4632
+ const content = await readFile(join(dir2, "credentials.json"), "utf-8");
4633
+ console.warn(
4634
+ "Warning: credentials.json is deprecated. New writes use moltnet.json. Support will be removed in 3 minor versions."
4635
+ );
4636
+ return JSON.parse(content);
4637
+ } catch {
4638
+ return null;
4639
+ }
4640
+ }
4641
+ async function writeConfig(config, configDir) {
4642
+ const dir2 = configDir ?? getConfigDir();
4643
+ await mkdir(dir2, { recursive: true });
4644
+ const filePath = join(dir2, "moltnet.json");
4645
+ await writeFile(filePath, JSON.stringify(config, null, 2) + "\n", {
4646
+ mode: 384
4647
+ });
4648
+ await chmod(filePath, 384);
4649
+ return filePath;
4650
+ }
4651
+ async function updateConfigSection(section, data, configDir) {
4652
+ const config = await readConfig(configDir);
4653
+ if (!config) {
4654
+ throw new Error("No config found — run `moltnet register` first");
4655
+ }
4656
+ const existing = config[section] ?? {};
4657
+ const updated = { ...existing, ...data };
4658
+ Object.assign(config, { [section]: updated });
4659
+ await writeConfig(config, configDir);
4660
+ }
4268
4661
  async function exportSSHKey(opts) {
4269
4662
  const config = await readConfig(opts == null ? void 0 : opts.configDir);
4270
4663
  if (!config) {
@@ -4393,16 +4786,91 @@ function buildGhTokenRule(agentName) {
4393
4786
  "# GitHub CLI Authentication (LeGreffier)",
4394
4787
  "",
4395
4788
  `When \`GIT_CONFIG_GLOBAL\` is set to \`.moltnet/${agentName}/gitconfig\`,`,
4396
- "authenticate all `gh` CLI commands as the GitHub App by prefixing them with:",
4789
+ "authenticate `gh` CLI commands as the GitHub App by prefixing them with:",
4397
4790
  "",
4398
4791
  "```bash",
4399
- 'GH_TOKEN=$(moltnet github token --credentials "$(dirname "$GIT_CONFIG_GLOBAL")/moltnet.json") gh <command>',
4792
+ 'GH_TOKEN=$(npx @themoltnet/cli github token --credentials "$(dirname "$GIT_CONFIG_GLOBAL")/moltnet.json") gh <command>',
4400
4793
  "```",
4401
4794
  "",
4402
- "This ensures `gh pr create`, `gh issue create`, etc. use the",
4403
- "GitHub App's identity instead of the user's personal token.",
4795
+ "The token is cached locally (~1 hour lifetime, 5-min expiry buffer),",
4796
+ "so repeated calls are fast after the first API hit.",
4797
+ "",
4798
+ "## Allowed `gh` subcommands",
4404
4799
  "",
4405
- "The token is short-lived (~1 hour) and generated on each invocation.",
4800
+ "The GitHub App only has these permissions:",
4801
+ "",
4802
+ "- `gh pr ...` (pull_requests: write)",
4803
+ "- `gh issue ...` (issues: write)",
4804
+ "- `gh api repos/{owner}/{repo}/contents/...` (contents: write)",
4805
+ "- `gh repo view`, `gh repo clone` (metadata: read + contents: read)",
4806
+ "",
4807
+ "Do NOT use `GH_TOKEN` for other `gh` commands (releases, actions, packages, etc.).",
4808
+ "",
4809
+ "## 401 recovery",
4810
+ "",
4811
+ "If you get a 401 error, the cached token may be stale. Delete",
4812
+ "`gh-token-cache.json` next to `moltnet.json` and retry.",
4813
+ ""
4814
+ ].join("\n");
4815
+ }
4816
+ function buildCodexRules(_agentName) {
4817
+ return [
4818
+ "# Codex sandbox rules for LeGreffier",
4819
+ "#",
4820
+ "# Allow the commands that the legreffier skill needs to run.",
4821
+ "# GH_TOKEN is injected inline; see $legreffier skill for details.",
4822
+ "",
4823
+ "# Read-only git commands (session activation & commit workflow)",
4824
+ "prefix_rule(",
4825
+ ' pattern = ["git", "config"],',
4826
+ ' decision = "allow",',
4827
+ ")",
4828
+ "prefix_rule(",
4829
+ ' pattern = ["git", "diff"],',
4830
+ ' decision = "allow",',
4831
+ ")",
4832
+ "prefix_rule(",
4833
+ ' pattern = ["git", "log"],',
4834
+ ' decision = "allow",',
4835
+ ")",
4836
+ "prefix_rule(",
4837
+ ' pattern = ["git", "rev-parse"],',
4838
+ ' decision = "allow",',
4839
+ ")",
4840
+ "prefix_rule(",
4841
+ ' pattern = ["git", "worktree", "list"],',
4842
+ ' decision = "allow",',
4843
+ ")",
4844
+ "",
4845
+ "# MoltNet CLI — signing & token generation",
4846
+ "prefix_rule(",
4847
+ ' pattern = ["npx", "@themoltnet/cli", "sign"],',
4848
+ ' decision = "allow",',
4849
+ ")",
4850
+ "prefix_rule(",
4851
+ ' pattern = ["npx", "@themoltnet/cli", "github", "token"],',
4852
+ ' decision = "allow",',
4853
+ ")",
4854
+ "prefix_rule(",
4855
+ ' pattern = ["moltnet", "sign"],',
4856
+ ' decision = "allow",',
4857
+ ")",
4858
+ "prefix_rule(",
4859
+ ' pattern = ["moltnet", "github", "token"],',
4860
+ ' decision = "allow",',
4861
+ ")",
4862
+ "",
4863
+ "# Worktree symlink creation",
4864
+ "prefix_rule(",
4865
+ ' pattern = ["ln", "-s"],',
4866
+ ' decision = "allow",',
4867
+ ")",
4868
+ "",
4869
+ "# Session activation env export",
4870
+ "prefix_rule(",
4871
+ ' pattern = ["echo"],',
4872
+ ' decision = "allow",',
4873
+ ")",
4406
4874
  ""
4407
4875
  ].join("\n");
4408
4876
  }
@@ -4422,6 +4890,8 @@ function buildPermissions(agentName) {
4422
4890
  "Bash(npx @themoltnet/cli github token *)",
4423
4891
  // Worktree symlink creation
4424
4892
  "Bash(ln -s *)",
4893
+ // Session activation env export
4894
+ 'Bash(echo "GIT_CONFIG_GLOBAL=*")',
4425
4895
  // All MCP tools for this agent's server
4426
4896
  `mcp__${agentName}__*`
4427
4897
  ];
@@ -4565,8 +5035,8 @@ class CodexAdapter {
4565
5035
  const dir2 = join(opts.repoDir, ".codex", "rules");
4566
5036
  await mkdir(dir2, { recursive: true });
4567
5037
  await writeFile(
4568
- join(dir2, "legreffier-gh.md"),
4569
- buildGhTokenRule(opts.agentName),
5038
+ join(dir2, "legreffier.rules"),
5039
+ buildCodexRules(opts.agentName),
4570
5040
  "utf-8"
4571
5041
  );
4572
5042
  }
@@ -4885,6 +5355,399 @@ async function runGitSetupPhase(opts) {
4885
5355
  );
4886
5356
  dispatch({ type: "step", key: "gitSetup", status: "done" });
4887
5357
  }
5358
+ function coerce(o) {
5359
+ if (o instanceof Uint8Array && o.constructor.name === "Uint8Array") {
5360
+ return o;
5361
+ }
5362
+ if (o instanceof ArrayBuffer) {
5363
+ return new Uint8Array(o);
5364
+ }
5365
+ if (ArrayBuffer.isView(o)) {
5366
+ return new Uint8Array(o.buffer, o.byteOffset, o.byteLength);
5367
+ }
5368
+ throw new Error("Unknown type, must be binary type");
5369
+ }
5370
+ function base(ALPHABET, name2) {
5371
+ if (ALPHABET.length >= 255) {
5372
+ throw new TypeError("Alphabet too long");
5373
+ }
5374
+ var BASE_MAP = new Uint8Array(256);
5375
+ for (var j = 0; j < BASE_MAP.length; j++) {
5376
+ BASE_MAP[j] = 255;
5377
+ }
5378
+ for (var i = 0; i < ALPHABET.length; i++) {
5379
+ var x = ALPHABET.charAt(i);
5380
+ var xc = x.charCodeAt(0);
5381
+ if (BASE_MAP[xc] !== 255) {
5382
+ throw new TypeError(x + " is ambiguous");
5383
+ }
5384
+ BASE_MAP[xc] = i;
5385
+ }
5386
+ var BASE = ALPHABET.length;
5387
+ var LEADER = ALPHABET.charAt(0);
5388
+ var FACTOR = Math.log(BASE) / Math.log(256);
5389
+ var iFACTOR = Math.log(256) / Math.log(BASE);
5390
+ function encode2(source) {
5391
+ if (source instanceof Uint8Array)
5392
+ ;
5393
+ else if (ArrayBuffer.isView(source)) {
5394
+ source = new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
5395
+ } else if (Array.isArray(source)) {
5396
+ source = Uint8Array.from(source);
5397
+ }
5398
+ if (!(source instanceof Uint8Array)) {
5399
+ throw new TypeError("Expected Uint8Array");
5400
+ }
5401
+ if (source.length === 0) {
5402
+ return "";
5403
+ }
5404
+ var zeroes = 0;
5405
+ var length = 0;
5406
+ var pbegin = 0;
5407
+ var pend = source.length;
5408
+ while (pbegin !== pend && source[pbegin] === 0) {
5409
+ pbegin++;
5410
+ zeroes++;
5411
+ }
5412
+ var size = (pend - pbegin) * iFACTOR + 1 >>> 0;
5413
+ var b58 = new Uint8Array(size);
5414
+ while (pbegin !== pend) {
5415
+ var carry = source[pbegin];
5416
+ var i2 = 0;
5417
+ for (var it1 = size - 1; (carry !== 0 || i2 < length) && it1 !== -1; it1--, i2++) {
5418
+ carry += 256 * b58[it1] >>> 0;
5419
+ b58[it1] = carry % BASE >>> 0;
5420
+ carry = carry / BASE >>> 0;
5421
+ }
5422
+ if (carry !== 0) {
5423
+ throw new Error("Non-zero carry");
5424
+ }
5425
+ length = i2;
5426
+ pbegin++;
5427
+ }
5428
+ var it2 = size - length;
5429
+ while (it2 !== size && b58[it2] === 0) {
5430
+ it2++;
5431
+ }
5432
+ var str = LEADER.repeat(zeroes);
5433
+ for (; it2 < size; ++it2) {
5434
+ str += ALPHABET.charAt(b58[it2]);
5435
+ }
5436
+ return str;
5437
+ }
5438
+ function decodeUnsafe(source) {
5439
+ if (typeof source !== "string") {
5440
+ throw new TypeError("Expected String");
5441
+ }
5442
+ if (source.length === 0) {
5443
+ return new Uint8Array();
5444
+ }
5445
+ var psz = 0;
5446
+ if (source[psz] === " ") {
5447
+ return;
5448
+ }
5449
+ var zeroes = 0;
5450
+ var length = 0;
5451
+ while (source[psz] === LEADER) {
5452
+ zeroes++;
5453
+ psz++;
5454
+ }
5455
+ var size = (source.length - psz) * FACTOR + 1 >>> 0;
5456
+ var b256 = new Uint8Array(size);
5457
+ while (source[psz]) {
5458
+ var carry = BASE_MAP[source.charCodeAt(psz)];
5459
+ if (carry === 255) {
5460
+ return;
5461
+ }
5462
+ var i2 = 0;
5463
+ for (var it3 = size - 1; (carry !== 0 || i2 < length) && it3 !== -1; it3--, i2++) {
5464
+ carry += BASE * b256[it3] >>> 0;
5465
+ b256[it3] = carry % 256 >>> 0;
5466
+ carry = carry / 256 >>> 0;
5467
+ }
5468
+ if (carry !== 0) {
5469
+ throw new Error("Non-zero carry");
5470
+ }
5471
+ length = i2;
5472
+ psz++;
5473
+ }
5474
+ if (source[psz] === " ") {
5475
+ return;
5476
+ }
5477
+ var it4 = size - length;
5478
+ while (it4 !== size && b256[it4] === 0) {
5479
+ it4++;
5480
+ }
5481
+ var vch = new Uint8Array(zeroes + (size - it4));
5482
+ var j2 = zeroes;
5483
+ while (it4 !== size) {
5484
+ vch[j2++] = b256[it4++];
5485
+ }
5486
+ return vch;
5487
+ }
5488
+ function decode2(string) {
5489
+ var buffer = decodeUnsafe(string);
5490
+ if (buffer) {
5491
+ return buffer;
5492
+ }
5493
+ throw new Error(`Non-${name2} character`);
5494
+ }
5495
+ return {
5496
+ encode: encode2,
5497
+ decodeUnsafe,
5498
+ decode: decode2
5499
+ };
5500
+ }
5501
+ var src = base;
5502
+ var _brrp__multiformats_scope_baseX = src;
5503
+ class Encoder2 {
5504
+ name;
5505
+ prefix;
5506
+ baseEncode;
5507
+ constructor(name2, prefix, baseEncode) {
5508
+ this.name = name2;
5509
+ this.prefix = prefix;
5510
+ this.baseEncode = baseEncode;
5511
+ }
5512
+ encode(bytes) {
5513
+ if (bytes instanceof Uint8Array) {
5514
+ return `${this.prefix}${this.baseEncode(bytes)}`;
5515
+ } else {
5516
+ throw Error("Unknown type, must be binary type");
5517
+ }
5518
+ }
5519
+ }
5520
+ class Decoder2 {
5521
+ name;
5522
+ prefix;
5523
+ baseDecode;
5524
+ prefixCodePoint;
5525
+ constructor(name2, prefix, baseDecode) {
5526
+ this.name = name2;
5527
+ this.prefix = prefix;
5528
+ const prefixCodePoint = prefix.codePointAt(0);
5529
+ if (prefixCodePoint === void 0) {
5530
+ throw new Error("Invalid prefix character");
5531
+ }
5532
+ this.prefixCodePoint = prefixCodePoint;
5533
+ this.baseDecode = baseDecode;
5534
+ }
5535
+ decode(text) {
5536
+ if (typeof text === "string") {
5537
+ if (text.codePointAt(0) !== this.prefixCodePoint) {
5538
+ throw Error(`Unable to decode multibase string ${JSON.stringify(text)}, ${this.name} decoder only supports inputs prefixed with ${this.prefix}`);
5539
+ }
5540
+ return this.baseDecode(text.slice(this.prefix.length));
5541
+ } else {
5542
+ throw Error("Can only multibase decode strings");
5543
+ }
5544
+ }
5545
+ or(decoder) {
5546
+ return or(this, decoder);
5547
+ }
5548
+ }
5549
+ class ComposedDecoder2 {
5550
+ decoders;
5551
+ constructor(decoders) {
5552
+ this.decoders = decoders;
5553
+ }
5554
+ or(decoder) {
5555
+ return or(this, decoder);
5556
+ }
5557
+ decode(input) {
5558
+ const prefix = input[0];
5559
+ const decoder = this.decoders[prefix];
5560
+ if (decoder != null) {
5561
+ return decoder.decode(input);
5562
+ } else {
5563
+ throw RangeError(`Unable to decode multibase string ${JSON.stringify(input)}, only inputs prefixed with ${Object.keys(this.decoders)} are supported`);
5564
+ }
5565
+ }
5566
+ }
5567
+ function or(left, right) {
5568
+ return new ComposedDecoder2({
5569
+ ...left.decoders ?? { [left.prefix]: left },
5570
+ ...right.decoders ?? { [right.prefix]: right }
5571
+ });
5572
+ }
5573
+ class Codec2 {
5574
+ name;
5575
+ prefix;
5576
+ baseEncode;
5577
+ baseDecode;
5578
+ encoder;
5579
+ decoder;
5580
+ constructor(name2, prefix, baseEncode, baseDecode) {
5581
+ this.name = name2;
5582
+ this.prefix = prefix;
5583
+ this.baseEncode = baseEncode;
5584
+ this.baseDecode = baseDecode;
5585
+ this.encoder = new Encoder2(name2, prefix, baseEncode);
5586
+ this.decoder = new Decoder2(name2, prefix, baseDecode);
5587
+ }
5588
+ encode(input) {
5589
+ return this.encoder.encode(input);
5590
+ }
5591
+ decode(input) {
5592
+ return this.decoder.decode(input);
5593
+ }
5594
+ }
5595
+ function from({ name: name2, prefix, encode: encode2, decode: decode2 }) {
5596
+ return new Codec2(name2, prefix, encode2, decode2);
5597
+ }
5598
+ function baseX({ name: name2, prefix, alphabet }) {
5599
+ const { encode: encode2, decode: decode2 } = _brrp__multiformats_scope_baseX(alphabet, name2);
5600
+ return from({
5601
+ prefix,
5602
+ name: name2,
5603
+ encode: encode2,
5604
+ decode: (text) => coerce(decode2(text))
5605
+ });
5606
+ }
5607
+ function decode(string, alphabetIdx, bitsPerChar, name2) {
5608
+ let end = string.length;
5609
+ while (string[end - 1] === "=") {
5610
+ --end;
5611
+ }
5612
+ const out = new Uint8Array(end * bitsPerChar / 8 | 0);
5613
+ let bits = 0;
5614
+ let buffer = 0;
5615
+ let written = 0;
5616
+ for (let i = 0; i < end; ++i) {
5617
+ const value = alphabetIdx[string[i]];
5618
+ if (value === void 0) {
5619
+ throw new SyntaxError(`Non-${name2} character`);
5620
+ }
5621
+ buffer = buffer << bitsPerChar | value;
5622
+ bits += bitsPerChar;
5623
+ if (bits >= 8) {
5624
+ bits -= 8;
5625
+ out[written++] = 255 & buffer >> bits;
5626
+ }
5627
+ }
5628
+ if (bits >= bitsPerChar || (255 & buffer << 8 - bits) !== 0) {
5629
+ throw new SyntaxError("Unexpected end of data");
5630
+ }
5631
+ return out;
5632
+ }
5633
+ function encode(data, alphabet, bitsPerChar) {
5634
+ const pad = alphabet[alphabet.length - 1] === "=";
5635
+ const mask = (1 << bitsPerChar) - 1;
5636
+ let out = "";
5637
+ let bits = 0;
5638
+ let buffer = 0;
5639
+ for (let i = 0; i < data.length; ++i) {
5640
+ buffer = buffer << 8 | data[i];
5641
+ bits += 8;
5642
+ while (bits > bitsPerChar) {
5643
+ bits -= bitsPerChar;
5644
+ out += alphabet[mask & buffer >> bits];
5645
+ }
5646
+ }
5647
+ if (bits !== 0) {
5648
+ out += alphabet[mask & buffer << bitsPerChar - bits];
5649
+ }
5650
+ if (pad) {
5651
+ while ((out.length * bitsPerChar & 7) !== 0) {
5652
+ out += "=";
5653
+ }
5654
+ }
5655
+ return out;
5656
+ }
5657
+ function createAlphabetIdx(alphabet) {
5658
+ const alphabetIdx = {};
5659
+ for (let i = 0; i < alphabet.length; ++i) {
5660
+ alphabetIdx[alphabet[i]] = i;
5661
+ }
5662
+ return alphabetIdx;
5663
+ }
5664
+ function rfc4648({ name: name2, prefix, bitsPerChar, alphabet }) {
5665
+ const alphabetIdx = createAlphabetIdx(alphabet);
5666
+ return from({
5667
+ prefix,
5668
+ name: name2,
5669
+ encode(input) {
5670
+ return encode(input, alphabet, bitsPerChar);
5671
+ },
5672
+ decode(input) {
5673
+ return decode(input, alphabetIdx, bitsPerChar, name2);
5674
+ }
5675
+ });
5676
+ }
5677
+ rfc4648({
5678
+ prefix: "b",
5679
+ name: "base32",
5680
+ alphabet: "abcdefghijklmnopqrstuvwxyz234567",
5681
+ bitsPerChar: 5
5682
+ });
5683
+ rfc4648({
5684
+ prefix: "B",
5685
+ name: "base32upper",
5686
+ alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
5687
+ bitsPerChar: 5
5688
+ });
5689
+ rfc4648({
5690
+ prefix: "c",
5691
+ name: "base32pad",
5692
+ alphabet: "abcdefghijklmnopqrstuvwxyz234567=",
5693
+ bitsPerChar: 5
5694
+ });
5695
+ rfc4648({
5696
+ prefix: "C",
5697
+ name: "base32padupper",
5698
+ alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=",
5699
+ bitsPerChar: 5
5700
+ });
5701
+ rfc4648({
5702
+ prefix: "v",
5703
+ name: "base32hex",
5704
+ alphabet: "0123456789abcdefghijklmnopqrstuv",
5705
+ bitsPerChar: 5
5706
+ });
5707
+ rfc4648({
5708
+ prefix: "V",
5709
+ name: "base32hexupper",
5710
+ alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUV",
5711
+ bitsPerChar: 5
5712
+ });
5713
+ rfc4648({
5714
+ prefix: "t",
5715
+ name: "base32hexpad",
5716
+ alphabet: "0123456789abcdefghijklmnopqrstuv=",
5717
+ bitsPerChar: 5
5718
+ });
5719
+ rfc4648({
5720
+ prefix: "T",
5721
+ name: "base32hexpadupper",
5722
+ alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUV=",
5723
+ bitsPerChar: 5
5724
+ });
5725
+ rfc4648({
5726
+ prefix: "h",
5727
+ name: "base32z",
5728
+ alphabet: "ybndrfg8ejkmcpqxot1uwisza345h769",
5729
+ bitsPerChar: 5
5730
+ });
5731
+ baseX({
5732
+ prefix: "k",
5733
+ name: "base36",
5734
+ alphabet: "0123456789abcdefghijklmnopqrstuvwxyz"
5735
+ });
5736
+ baseX({
5737
+ prefix: "K",
5738
+ name: "base36upper",
5739
+ alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
5740
+ });
5741
+ baseX({
5742
+ name: "base58btc",
5743
+ prefix: "z",
5744
+ alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
5745
+ });
5746
+ baseX({
5747
+ name: "base58flickr",
5748
+ prefix: "Z",
5749
+ alphabet: "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
5750
+ });
4888
5751
  etc.sha512Sync = (...m) => {
4889
5752
  const hash = createHash("sha512");
4890
5753
  m.forEach((msg) => hash.update(msg));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@themoltnet/legreffier",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "LeGreffier — one-command accountable AI agent setup",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -35,8 +35,8 @@
35
35
  "vitest": "^3.0.0",
36
36
  "@moltnet/api-client": "0.1.0",
37
37
  "@moltnet/crypto-service": "0.1.0",
38
- "@moltnet/design-system": "0.1.0",
39
- "@themoltnet/sdk": "0.50.0"
38
+ "@themoltnet/sdk": "0.51.0",
39
+ "@moltnet/design-system": "0.1.0"
40
40
  },
41
41
  "scripts": {
42
42
  "dev": "vite build --watch",