gm-skill 2.0.2487 → 2.0.2489

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-plugkit",
3
- "version": "2.0.2487",
3
+ "version": "2.0.2489",
4
4
  "description": "Bootstrap and daemon-spawn tool for gm plugkit binary. Downloads the correct platform wasm, verifies SHA256, and launches agentplug-runner (the native wasm host) as the spool watcher daemon.",
5
5
  "main": "index.js",
6
6
  "bin": {
package/gm.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm",
3
- "version": "2.0.2487",
3
+ "version": "2.0.2489",
4
4
  "description": "Spool-dispatch orchestration engine with unified state machine, skills, and automated git enforcement",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-skill",
3
- "version": "2.0.2487",
3
+ "version": "2.0.2489",
4
4
  "description": "Canonical universal harness — AI-native software engineering via skill-driven orchestration; bootstraps plugkit for task execution and session isolation. Install in any AI coding agent host.",
5
5
  "author": "AnEntrypoint",
6
6
  "license": "MIT",
@@ -0,0 +1,194 @@
1
+ #!/usr/bin/env node
2
+ // Migrates gm's default memory corpus (.gm/memories/*.md + any legacy
3
+ // .gm/rs-learn.db, if present) into the opt-in tencentdb_backend
4
+ // (memory.tencentdb_backend in gm.config.json). Discards superfluous
5
+ // content (git-log-derivable facts, dated audit entries, historical
6
+ // "we used to" framing) using the same heuristic rs-plugkit's own
7
+ // memorize-fire already applies at write time (orchestrator/memorize.rs's
8
+ // is_derivable_state), so migrated content is held to the same bar new
9
+ // memories already are, not a looser one.
10
+ //
11
+ // Idempotent: re-running produces zero new writes for content already
12
+ // migrated, since the target backend dedupes by the same
13
+ // namespace|text content-hash key scheme gm's memorize verb uses.
14
+ //
15
+ // Usage:
16
+ // node scripts/migrate-memory-to-tencentdb.mjs --project <path> [--namespace default] [--dry-run]
17
+ //
18
+ // Requires the target project to have a live gm-plugkit spool watcher
19
+ // (boots one if .gm/exec-spool is missing, same as any other gm session)
20
+ // and memory.tencentdb_backend.enabled=true with the target namespace
21
+ // listed in gm.config.json -- this script drives the memorize verb, never
22
+ // writes .gm/tencentdb-memory files directly, so the write always goes
23
+ // through the same dedup/embed/index path a live agent dispatch would.
24
+
25
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
26
+ import { join } from "node:path";
27
+ import { execFileSync } from "node:child_process";
28
+
29
+ const args = process.argv.slice(2);
30
+ const DRY_RUN = args.includes("--dry-run");
31
+ const projectIdx = args.indexOf("--project");
32
+ const PROJECT = projectIdx >= 0 ? args[projectIdx + 1] : process.cwd();
33
+ const nsIdx = args.indexOf("--namespace");
34
+ const NAMESPACE = nsIdx >= 0 ? args[nsIdx + 1] : "default";
35
+
36
+ const SPOOL_IN = join(PROJECT, ".gm", "exec-spool", "in");
37
+ const SPOOL_OUT = join(PROJECT, ".gm", "exec-spool", "out");
38
+ const MEMORIES_DIR = join(PROJECT, ".gm", "memories");
39
+ const RS_LEARN_DB = join(PROJECT, ".gm", "rs-learn.db");
40
+
41
+ // Mirrors rs-plugkit's orchestrator/memorize.rs::is_derivable_state exactly
42
+ // (pattern list kept in sync by hand -- both are small and rarely change;
43
+ // a mismatch here would only ever under- or over-reject, never corrupt
44
+ // data, since the actual write still goes through gm's own memorize verb
45
+ // which re-applies its own copy of this check).
46
+ function isDerivableState(text) {
47
+ const t = text.trim();
48
+ if (t.length > 40 && /^[0-9a-fA-F]+$/.test(t)) {
49
+ return "memo is a hex hash; git log is the source of truth";
50
+ }
51
+ const lower = t.toLowerCase();
52
+ const bad = [
53
+ ["we used to ", "historical framing belongs in git log + CHANGELOG"],
54
+ ["used to do", "historical framing belongs in git log + CHANGELOG"],
55
+ ["previously did", "historical framing belongs in git log + CHANGELOG"],
56
+ ["(fixed)", "past-tense fix markers belong in commit messages"],
57
+ ["fixed in commit", "commit-fix references belong in git log"],
58
+ ["fix in commit", "commit-fix references belong in git log"],
59
+ ["changelog:", "changelog entries live in CHANGELOG.md"],
60
+ ["changelog entry", "changelog entries live in CHANGELOG.md"],
61
+ ["dated audit", "dated audit entries belong in git log"],
62
+ ["(added 20", "dated annotations belong in git log"],
63
+ ["commit hash", "commit hashes are derivable from git log"],
64
+ ["recent commit", "recent commits are derivable from git log"],
65
+ ["git blame says", "git blame is derivable from the repo"],
66
+ ];
67
+ for (const [pat, reason] of bad) {
68
+ if (lower.includes(pat)) return reason;
69
+ }
70
+ return null;
71
+ }
72
+
73
+ // Parses memory_md.rs's frontmatter format:
74
+ // ---\nkey: ...\nns: ...\ncreated: <ms>\nupdated: <ms>\n---\n\n<body>\n
75
+ function parseMemoryFile(raw) {
76
+ const m = raw.match(/^---\n([\s\S]*?)\n---\n\n([\s\S]*)$/);
77
+ if (!m) return null;
78
+ const [, frontmatter, body] = m;
79
+ const fields = {};
80
+ for (const line of frontmatter.split("\n")) {
81
+ const idx = line.indexOf(":");
82
+ if (idx === -1) continue;
83
+ fields[line.slice(0, idx).trim()] = line.slice(idx + 1).trim();
84
+ }
85
+ return { key: fields.key, ns: fields.ns, created: fields.created, updated: fields.updated, text: body.trimEnd() };
86
+ }
87
+
88
+ function listMemoryFiles(namespace) {
89
+ const dir = namespace === "default"
90
+ ? MEMORIES_DIR
91
+ : join(PROJECT, ".gm", "disciplines", namespace, "memories");
92
+ if (!existsSync(dir)) return [];
93
+ return readdirSync(dir)
94
+ .filter((f) => f.endsWith(".md"))
95
+ .map((f) => join(dir, f))
96
+ .filter((p) => statSync(p).isFile());
97
+ }
98
+
99
+ function probeLegacyRsLearnDb() {
100
+ if (!existsSync(RS_LEARN_DB)) return { present: false };
101
+ // rs-learn.db is a retired sqlite/libsql file; rs-plugkit's own
102
+ // legacy_reaper.rs deletes it outright on its next reap pass (no
103
+ // migration path -- the crate implementing it is gone, its schema was
104
+ // never documented, and nothing in the current codebase reads it). This
105
+ // script only reports its presence/size so an operator knows it existed
106
+ // and was NOT migrated (it predates the current .gm/memories corpus,
107
+ // which is the actual source of truth this script migrates from).
108
+ const size = statSync(RS_LEARN_DB).size;
109
+ return { present: true, sizeBytes: size, note: "not migrated -- retired format with no readable schema; will be deleted by rs-plugkit's own legacy_reaper on its next pass" };
110
+ }
111
+
112
+ function dispatchVerb(verb, body, timeoutMs = 30_000) {
113
+ const n = `${Date.now()}${Math.floor(Math.random() * 1e6)}`;
114
+ const inDir = join(SPOOL_IN, verb);
115
+ const outPath = join(SPOOL_OUT, `${verb}-${n}.json`);
116
+ execFileSync("mkdir", ["-p", inDir]);
117
+ execFileSync("node", ["-e", `require('fs').writeFileSync(${JSON.stringify(join(inDir, `${n}.txt`))}, ${JSON.stringify(JSON.stringify(body))})`]);
118
+ const deadline = Date.now() + timeoutMs;
119
+ while (Date.now() < deadline) {
120
+ if (existsSync(outPath)) {
121
+ try {
122
+ return JSON.parse(readFileSync(outPath, "utf8"));
123
+ } catch {
124
+ // file still being written; keep polling
125
+ }
126
+ }
127
+ execFileSync("sleep", ["0.2"]);
128
+ }
129
+ throw new Error(`dispatch timeout waiting for ${outPath}`);
130
+ }
131
+
132
+ function main() {
133
+ console.log(`[migrate] project=${PROJECT} namespace=${NAMESPACE} dry-run=${DRY_RUN}`);
134
+
135
+ const legacy = probeLegacyRsLearnDb();
136
+ if (legacy.present) {
137
+ console.log(`[migrate] legacy .gm/rs-learn.db found (${legacy.sizeBytes} bytes) -- ${legacy.note}`);
138
+ }
139
+
140
+ const files = listMemoryFiles(NAMESPACE);
141
+ console.log(`[migrate] found ${files.length} memory files in namespace "${NAMESPACE}"`);
142
+
143
+ let kept = 0;
144
+ let discarded = 0;
145
+ let errored = 0;
146
+ const discardedSamples = [];
147
+
148
+ for (const path of files) {
149
+ const raw = readFileSync(path, "utf8");
150
+ const parsed = parseMemoryFile(raw);
151
+ if (!parsed || !parsed.text) {
152
+ errored++;
153
+ console.log(`[migrate] ERROR: ${path} does not match the expected memory_md.rs frontmatter format, skipping`);
154
+ continue;
155
+ }
156
+ const reason = isDerivableState(parsed.text);
157
+ if (reason) {
158
+ discarded++;
159
+ if (discardedSamples.length < 10) {
160
+ discardedSamples.push({ key: parsed.key, reason, preview: parsed.text.slice(0, 80) });
161
+ }
162
+ continue;
163
+ }
164
+ if (DRY_RUN) {
165
+ kept++;
166
+ continue;
167
+ }
168
+ try {
169
+ const resp = dispatchVerb("memorize", { text: parsed.text, namespace: NAMESPACE, kind: "l0" });
170
+ if (resp.ok) {
171
+ kept++;
172
+ } else {
173
+ errored++;
174
+ console.log(`[migrate] ERROR migrating ${parsed.key}: ${resp.error || JSON.stringify(resp)}`);
175
+ }
176
+ } catch (e) {
177
+ errored++;
178
+ console.log(`[migrate] ERROR migrating ${parsed.key}: ${e.message}`);
179
+ }
180
+ }
181
+
182
+ console.log(`[migrate] summary: kept=${kept} discarded=${discarded} errored=${errored} total=${files.length}`);
183
+ if (discardedSamples.length) {
184
+ console.log(`[migrate] sample of discarded entries (up to 10):`);
185
+ for (const s of discardedSamples) {
186
+ console.log(`[migrate] ${s.key}: ${s.reason} -- "${s.preview}${s.preview.length === 80 ? "..." : ""}"`);
187
+ }
188
+ }
189
+ if (DRY_RUN) {
190
+ console.log(`[migrate] dry-run: no writes performed. Re-run without --dry-run to migrate ${kept} memories.`);
191
+ }
192
+ }
193
+
194
+ main();
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: agent-memory
3
- description: Sets up and drives TencentDB Agent Memory (MemoryCore + MemoryHub + MemoryProxy + MemoryPanel, from AnEntrypoint/agent-memory) -- a persistent, cross-session memory and knowledge system for AI agents distinct from this project's own recall/memorize-fire store. Chat Memory (L0 conversation -> L1 atom -> L2 scenario -> L3 persona), a versioned Skill library extracted from past work, a Wiki + CodeGraph knowledge map over docs and code, and a human-controlled review panel. Use when the user wants an agent team to share and accumulate memory/skills/knowledge across sessions and across multiple agent frameworks (not just this one Claude Code session), when they mention "memory hub", "team memory", "chat memory", "skill library", "wiki", "codegraph", or ask to install/configure/troubleshoot the memory-tencentdb plugin, or when onboarding a new agent into an existing team's accumulated experience. Not for this project's own internal recall/memorize-fire mechanism -- that is a separate, unrelated store.
3
+ description: Sets up and drives TencentDB Agent Memory (MemoryCore + MemoryHub + MemoryProxy + MemoryPanel, from AnEntrypoint/agent-memory) -- a persistent, cross-session memory and knowledge system for AI agents. Chat Memory (L0 conversation -> L1 atom -> L2 scenario -> L3 persona), a versioned Skill library extracted from past work, a Wiki + CodeGraph knowledge map over docs and code, and a human-controlled review panel. Use when the user wants an agent team to share and accumulate memory/skills/knowledge across sessions and across multiple agent frameworks (not just this one Claude Code session), when they mention "memory hub", "team memory", "chat memory", "skill library", "wiki", "codegraph", or ask to install/configure/troubleshoot the memory-tencentdb plugin, or when onboarding a new agent into an existing team's accumulated experience. As of gm's tencentdb_backend addition, this system's format can ALSO be gm's own memorize/recall/memorize-fire/memorize-prune backend for an opted-in namespace (see gm.config.json's memory.tencentdb_backend) -- when that's enabled, the verb surface an agent already knows is unchanged; only the storage target moves. Use this skill for the standalone deployment (Docker Compose, panel UI, team review) or when gm's own backend is not what's being asked about.
4
4
  license: MIT
5
5
  compatibility: Requires Docker (or Node.js >= 22.16 for source install) to run MemoryCore/MemoryHub/MemoryProxy services locally or self-hosted; a running LLM endpoint (OpenAI-compatible) for extraction/embedding. Panel UI served over HTTP. Verified against AnEntrypoint/agent-memory (published fork of TencentCloud/TencentDB-Agent-Memory).
6
6
  metadata:
@@ -12,7 +12,7 @@ allowed-tools: Skill, Read, Write, Bash, WebFetch
12
12
 
13
13
  # agent-memory
14
14
 
15
- TencentDB Agent Memory gives an agent team a shared, growing memory instead of starting cold every session. It is a separate system from this project's own `memorize-fire`/`recall` store (see `wfgy-method`/`gm` skills for that) -- reach for `agent-memory` when the ask spans multiple agent frameworks, multiple team members, or needs a human-reviewable panel, not just this single Claude Code session's local recall.
15
+ TencentDB Agent Memory gives an agent team a shared, growing memory instead of starting cold every session. Two ways it relates to gm's own `memorize-fire`/`recall` (see `wfgy-method`/`gm` skills for that): (1) as a fully standalone system (this skill's main content, below) when the ask spans multiple agent frameworks, multiple team members, or needs a human-reviewable panel; (2) as an opt-in storage backend for gm's own memory verbs (`memory.tencentdb_backend` in `gm.config.json`, disabled by default) -- when a namespace is routed to it, gm's `memorize`/`recall`/`memorize-fire`/`memorize-prune` write file-pointer-indexed content compatible with this system's format instead of gm's default 384-dim md-corpus store, with no change to the verb surface an agent calls. Reach for THIS skill's setup instructions (Docker Compose, panel UI) for the standalone deployment; reach for `gm`'s own docs when the ask is just "make gm's memory use the Tencent-compatible backend."
16
16
 
17
17
  ## What it provides
18
18
 
@@ -23,10 +23,10 @@ TencentDB Agent Memory gives an agent team a shared, growing memory instead of s
23
23
 
24
24
  Assets are portable across agent frameworks and shareable across a team -- a new agent or team member can load existing memory instead of relearning from scratch.
25
25
 
26
- ## When to use this skill vs. this project's own memory
26
+ ## When to use this skill vs. gm's own memory verbs
27
27
 
28
- - Use `agent-memory` when: the user explicitly names TencentDB/memory-tencentdb/Memory Hub/team memory, wants memory that survives across *different* agent frameworks or team members (not just this session), wants a Skill library extracted from past conversations, or wants a Wiki/CodeGraph over a codebase.
29
- - Do NOT use this for the recall/memorize-fire mechanism already built into `gm`/`wfgy-method` -- that is this project's own local memory and is unrelated infrastructure.
28
+ - Use `agent-memory`'s standalone setup instructions when: the user explicitly names TencentDB/memory-tencentdb/Memory Hub/team memory, wants memory that survives across *different* agent frameworks or team members (not just this session), wants a Skill library extracted from past conversations, or wants a Wiki/CodeGraph over a codebase.
29
+ - Use gm's own `memorize`/`recall`/`memorize-fire`/`memorize-prune` verbs (default backend, no setup) for this session's own local recall -- and if the user specifically wants gm's memory to be Tencent-format-compatible without running the standalone services, point them at `gm.config.json`'s `memory.tencentdb_backend` block instead of a full standalone install.
30
30
 
31
31
  ## Setup
32
32