@themoltnet/legreffier 0.29.0 → 0.29.1

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 +16 -8
  2. package/dist/index.js +58 -27
  3. package/package.json +4 -4
package/README.md CHANGED
@@ -1,19 +1,27 @@
1
1
  # @themoltnet/legreffier
2
2
 
3
- One-command setup for accountable AI agent commits on
3
+ End-to-end attribution for AI coding agents — so you know who wrote the code,
4
+ why, and whether the context behind it actually worked. Built on
4
5
  [MoltNet](https://themolt.net).
5
6
 
6
- `legreffier init` generates a cryptographic identity, creates a GitHub App,
7
- configures git signing, and wires up your AI coding agent — all in one
8
- interactive flow.
7
+ `legreffier init` gives your agent its own cryptographic identity, a persistent
8
+ diary for decisions and rationale, and SSH-signed commits linked to signed
9
+ reasoning — all wired up in one interactive flow. Memory that's _attributed_,
10
+ rationale that's _signed_, and context that can be _measured_ — across sessions
11
+ and across agents.
9
12
 
10
13
  ## What You Get
11
14
 
12
15
  1. **Own identity** — commits show the agent's name and avatar, not yours
13
- 2. **SSH-signed commits** — every commit is signed with the agent's Ed25519 key
14
- 3. **Signed diary entries** non-trivial commits get a cryptographic rationale
15
- linked via a `MoltNet-Diary:` trailer
16
- 4. **GitHub App authentication** push access via installation tokens, no
16
+ 2. **Persistent diary** — signed, content-addressed entries for decisions,
17
+ rationale, and context that survive across sessions and across agents
18
+ 3. **Rationale linked to code** — non-trivial commits carry a `MoltNet-Diary:`
19
+ trailer pointing at a signed entry explaining _why_
20
+ 4. **SSH-signed commits** — every commit is signed with the agent's Ed25519 key
21
+ 5. **Measured context** — compiled packs can be scored against real coding
22
+ tasks via the MoltNet eval runner, so memory earns its place instead of just
23
+ accumulating
24
+ 6. **GitHub App authentication** — push access via installation tokens, no
17
25
  personal access tokens
18
26
 
19
27
  ## Prerequisites
package/dist/index.js CHANGED
@@ -410,14 +410,14 @@ function CliHero({ animated = false }) {
410
410
  /* @__PURE__ */ jsx(Text, { children: " " }),
411
411
  /* @__PURE__ */ jsxs(Text, { children: [
412
412
  " ",
413
- /* @__PURE__ */ jsx(Text, {
413
+ /* @__PURE__ */ jsxs(Text, {
414
414
  color: cliTheme.color.text,
415
- children: "Accountable AI commits. "
415
+ children: ["Attribution for AI coding agents.", " "]
416
416
  }),
417
417
  /* @__PURE__ */ jsx(Text, {
418
418
  color: cliTheme.color.accent,
419
419
  bold: true,
420
- children: "Cryptographic identity."
420
+ children: "Identity, memory, signed rationale."
421
421
  })
422
422
  ] }),
423
423
  /* @__PURE__ */ jsxs(Text, { children: [
@@ -7532,33 +7532,60 @@ async function downloadSkills(repoDir, skillDir) {
7532
7532
  }
7533
7533
  }
7534
7534
  }
7535
- function buildGhTokenRule(agentName) {
7535
+ function buildGhTokenRule() {
7536
7536
  return [
7537
- "# GitHub CLI Authentication (LeGreffier)",
7537
+ "# GitHub CLI Authentication (MoltNet agents)",
7538
+ "",
7539
+ "> **STRICT RULE — read this before every `gh` call.**",
7540
+ ">",
7541
+ "> When `GIT_CONFIG_GLOBAL` is set (matches `.moltnet/<agent>/gitconfig`), you",
7542
+ "> **MUST NOT** run bare `gh <command>`. You **MUST** prefix every `gh` call",
7543
+ "> with a `GH_TOKEN` resolved from an **absolute path** to `moltnet.json`.",
7544
+ "> Running bare `gh` silently falls back to the human personal token and",
7545
+ "> attributes the action to the wrong identity — this is a correctness bug,",
7546
+ "> not a warning.",
7538
7547
  "",
7539
- `When \`GIT_CONFIG_GLOBAL\` is set to \`.moltnet/${agentName}/gitconfig\`,`,
7540
- "authenticate `gh` CLI commands as the GitHub App by prefixing them with:",
7548
+ "## The only correct form",
7541
7549
  "",
7542
7550
  "```bash",
7543
- "GH_TOKEN=$(npx @themoltnet/cli github token --credentials \"$(dirname \"$GIT_CONFIG_GLOBAL\")/moltnet.json\") gh <command>",
7551
+ "# 1. Resolve credentials to an ABSOLUTE path (never trust $GIT_CONFIG_GLOBAL as-is).",
7552
+ "CREDS=\"$(cd \"$(dirname \"$GIT_CONFIG_GLOBAL\")\" 2>/dev/null && pwd)/moltnet.json\"",
7553
+ "",
7554
+ "# 2. Refuse to proceed if the file does not exist at that absolute path.",
7555
+ "[ -f \"$CREDS\" ] || { echo \"FATAL: moltnet.json not found at $CREDS\" >&2; exit 1; }",
7556
+ "",
7557
+ "# 3. Call gh with GH_TOKEN inlined.",
7558
+ "GH_TOKEN=$(npx @themoltnet/cli github token --credentials \"$CREDS\") gh <command>",
7544
7559
  "```",
7545
7560
  "",
7546
- "The token is cached locally (~1 hour lifetime, 5-min expiry buffer),",
7561
+ "The credentials file (`moltnet.json`) always lives next to the `gitconfig`",
7562
+ "inside the same `.moltnet/<agent>/` directory, regardless of which agent is",
7563
+ "active. The token is cached locally (~1 hour lifetime, 5-min expiry buffer),",
7547
7564
  "so repeated calls are fast after the first API hit.",
7548
7565
  "",
7549
- "## Worktree warning",
7566
+ "## Why absolute paths are mandatory",
7550
7567
  "",
7551
- `\`GIT_CONFIG_GLOBAL\` may be a **relative path** (e.g. \`.moltnet/${agentName}/gitconfig\`).`,
7552
- "In git worktrees the CWD differs from the main worktree root, so `$(dirname \"$GIT_CONFIG_GLOBAL\")`",
7553
- "resolves incorrectly and `no credentials found` is printed the command then falls back to your",
7554
- "personal `gh` token silently.",
7568
+ "`GIT_CONFIG_GLOBAL` is almost always a **relative path** (e.g. `.moltnet/<agent>/gitconfig`).",
7569
+ "Every git worktree has a different CWD from the main worktree root, so",
7570
+ "`$(dirname \"$GIT_CONFIG_GLOBAL\")` resolves differently depending on where you are.",
7571
+ "When it resolves to a non-existent directory:",
7555
7572
  "",
7556
- "**Always resolve to an absolute path first:**",
7573
+ "- `npx @themoltnet/cli github token` prints `no credentials found` to stderr,",
7574
+ "- the command substitution yields an empty `GH_TOKEN`,",
7575
+ "- `gh` silently falls back to your personal token,",
7576
+ "- the resulting API call is attributed to the **human**, not the agent.",
7557
7577
  "",
7558
- "```bash",
7559
- "CREDS=\"$(cd \"$(dirname \"$GIT_CONFIG_GLOBAL\")\" && pwd)/moltnet.json\"",
7560
- "GH_TOKEN=$(npx @themoltnet/cli github token --credentials \"$CREDS\") gh <command>",
7561
- "```",
7578
+ "This failure is invisible in normal output. The `cd ... && pwd` dance in step 1",
7579
+ "is the only reliable way to get an absolute path that works across worktrees.",
7580
+ "",
7581
+ "## Forbidden patterns",
7582
+ "",
7583
+ "- `gh <command>` — bare, no `GH_TOKEN`. **Never.**",
7584
+ "- `GH_TOKEN=$(... --credentials \"$(dirname \"$GIT_CONFIG_GLOBAL\")/moltnet.json\") gh ...`",
7585
+ " — uses the raw relative path. Breaks in worktrees.",
7586
+ "- `GH_TOKEN=$(... --credentials \"./moltnet.json\") gh ...` — relative. Breaks.",
7587
+ "- `GH_TOKEN=$(... --credentials \"~/.moltnet/...\") gh ...` — `~` is not expanded",
7588
+ " inside double quotes; use `$HOME` or the literal absolute path.",
7562
7589
  "",
7563
7590
  "## Allowed `gh` subcommands",
7564
7591
  "",
@@ -7780,7 +7807,7 @@ var ClaudeAdapter = class {
7780
7807
  async writeRules(opts) {
7781
7808
  const dir = join(opts.repoDir, ".claude", "rules");
7782
7809
  await mkdir(dir, { recursive: true });
7783
- await writeFile(join(dir, "legreffier-gh.md"), buildGhTokenRule(opts.agentName), "utf-8");
7810
+ await writeFile(join(dir, "legreffier-gh.md"), buildGhTokenRule(), "utf-8");
7784
7811
  }
7785
7812
  };
7786
7813
  //#endregion
@@ -8057,17 +8084,21 @@ async function writePem(pem, appSlug, configDir) {
8057
8084
  /**
8058
8085
  * Write a standalone gitconfig file to <configDir>/gitconfig and return
8059
8086
  * its path. The config sets user.name/email and enables SSH commit signing
8060
- * using the agent's SSH key.
8087
+ * using the agent's SSH public key.
8088
+ *
8089
+ * **Important:** `signingkey` must live under `[user]`, not `[gpg "ssh"]`.
8090
+ * Git only reads `user.signingkey`; a key declared as `gpg.ssh.signingkey`
8091
+ * is silently ignored and `git commit -S` fails with
8092
+ * `fatal: either user.signingkey or gpg.ssh.defaultKeyCommand needs to be configured`.
8061
8093
  */
8062
- async function writeGitConfig({ configDir, name, email, sshKeyPath }) {
8094
+ async function writeGitConfig({ configDir, name, email, sshPublicKeyPath }) {
8063
8095
  const content = [
8064
8096
  "[user]",
8065
8097
  `\tname = ${name}`,
8066
8098
  `\temail = ${email}`,
8099
+ `\tsigningkey = ${sshPublicKeyPath}`,
8067
8100
  "[gpg]",
8068
8101
  " format = ssh",
8069
- "[gpg \"ssh\"]",
8070
- `\tsigningKey = ${sshKeyPath}`,
8071
8102
  "[commit]",
8072
8103
  " gpgsign = true",
8073
8104
  ""
@@ -8322,7 +8353,7 @@ async function runGitSetupPhase(opts) {
8322
8353
  key: "gitSetup",
8323
8354
  status: "running"
8324
8355
  });
8325
- const { privatePath } = await exportSSHKey({ configDir });
8356
+ const { publicPath } = await exportSSHKey({ configDir });
8326
8357
  const email = buildBotEmail((await lookupBotUser(appSlug, { maxRetries: 5 })).id, appSlug);
8327
8358
  await updateConfigSection("git", {
8328
8359
  name: agentName,
@@ -8332,7 +8363,7 @@ async function runGitSetupPhase(opts) {
8332
8363
  configDir,
8333
8364
  name: agentName,
8334
8365
  email,
8335
- sshKeyPath: privatePath
8366
+ sshPublicKeyPath: publicPath
8336
8367
  })
8337
8368
  }, configDir);
8338
8369
  dispatch({
@@ -9252,7 +9283,7 @@ async function runPortRewritePhase(opts) {
9252
9283
  configDir: targetDir,
9253
9284
  name: config.git.name,
9254
9285
  email: config.git.email,
9255
- sshKeyPath: newSshPriv
9286
+ sshPublicKeyPath: newSshPub
9256
9287
  });
9257
9288
  await writeEnvFile({
9258
9289
  envDir: targetDir,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@themoltnet/legreffier",
3
- "version": "0.29.0",
4
- "description": "LeGreffier — one-command accountable AI agent setup",
3
+ "version": "0.29.1",
4
+ "description": "LeGreffier — attribution and measured memory for AI coding agents.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "module",
7
7
  "repository": {
@@ -36,8 +36,8 @@
36
36
  "@moltnet/api-client": "0.1.0",
37
37
  "@themoltnet/design-system": "0.3.2",
38
38
  "@moltnet/crypto-service": "0.1.0",
39
- "@themoltnet/github-agent": "0.23.0",
40
- "@themoltnet/sdk": "0.88.0"
39
+ "@themoltnet/sdk": "0.88.0",
40
+ "@themoltnet/github-agent": "0.23.0"
41
41
  },
42
42
  "scripts": {
43
43
  "dev": "vite build --watch",