aidimag 1.0.9 → 1.0.11
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/dist/cli/commands/memory.js +6 -5
- package/dist/cli/commands/sync.js +28 -9
- package/dist/sync/client.d.ts +4 -4
- package/dist/sync/client.js +20 -14
- package/package.json +1 -1
|
@@ -73,11 +73,10 @@ This project uses aiDimag for persistent memory. Always consult memory before pr
|
|
|
73
73
|
const current = existsSync(rootIgnore) ? readFileSync(rootIgnore, "utf8") : "";
|
|
74
74
|
const folder = resolveKnowledgeConfig(root).folder;
|
|
75
75
|
const additions = [];
|
|
76
|
-
if (!current.includes(".aidimag
|
|
77
|
-
additions.push(".aidimag
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
additions.push(`${folder}/*`, `!${folder}/.gitkeep`);
|
|
76
|
+
if (!current.includes(".aidimag"))
|
|
77
|
+
additions.push(".aidimag");
|
|
78
|
+
if (!current.includes(folder))
|
|
79
|
+
additions.push(folder);
|
|
81
80
|
// generated context files (users can commit them if they want, but default is gitignored)
|
|
82
81
|
if (!current.includes("CLAUDE.md"))
|
|
83
82
|
additions.push("CLAUDE.md");
|
|
@@ -87,6 +86,8 @@ This project uses aiDimag for persistent memory. Always consult memory before pr
|
|
|
87
86
|
additions.push(".windsurfrules");
|
|
88
87
|
if (!current.includes("AGENTS.md"))
|
|
89
88
|
additions.push("AGENTS.md");
|
|
89
|
+
if (!current.includes(".github/copilot-instructions.md"))
|
|
90
|
+
additions.push(".github/copilot-instructions.md");
|
|
90
91
|
if (additions.length) {
|
|
91
92
|
appendFileSync(rootIgnore, `${current.endsWith("\n") || current === "" ? "" : "\n"}${additions.join("\n")}\n`);
|
|
92
93
|
console.log(`\nUpdated ${rootIgnore} (ignored memory.db + ${folder}/ drops + generated context files)`);
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Team-sync commands: serve, cloud, login, logout, sync, keys.
|
|
3
3
|
*/
|
|
4
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
4
5
|
import { MemoryStore, findRepoRoot } from "../../db/store.js";
|
|
5
6
|
import { fail, maybeRegenerateContext, openBrowser, createPrompter } from "../shared.js";
|
|
7
|
+
import { configPath } from "../../sync/client.js";
|
|
6
8
|
export function registerSyncCommands(program) {
|
|
7
9
|
program
|
|
8
10
|
.command("serve")
|
|
@@ -25,7 +27,7 @@ export function registerSyncCommands(program) {
|
|
|
25
27
|
.argument("<action>", "link | unlink | status | remote")
|
|
26
28
|
.option("-s, --server <url>", "Sync server URL")
|
|
27
29
|
.option("-b, --brain <name>", "Brain (team memory) name on the server")
|
|
28
|
-
.option("-t, --token <token>", "Auth token (stored in
|
|
30
|
+
.option("-t, --token <token>", "Auth token (stored in .aidimag/config.json)")
|
|
29
31
|
.option("--json", "Machine-readable output (remote)")
|
|
30
32
|
.option("--id <memoryId>", "Show one remote memory by id (remote)")
|
|
31
33
|
.option("--limit <n>", "Max rows to list (remote)", "20")
|
|
@@ -41,13 +43,28 @@ export function registerSyncCommands(program) {
|
|
|
41
43
|
if (!opts.server || !opts.brain)
|
|
42
44
|
fail("usage: dim cloud link --server <url> --brain <name> [--token <token>]");
|
|
43
45
|
const server = String(opts.server).replace(/\/$/, "");
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
// Always store token in project config
|
|
47
|
+
const p = configPath(root);
|
|
48
|
+
let existing = {};
|
|
49
|
+
try {
|
|
50
|
+
existing = JSON.parse(readFileSync(p, "utf8"));
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// fresh file
|
|
54
|
+
}
|
|
55
|
+
const newConfig = { ...existing, server, brain: opts.brain };
|
|
56
|
+
if (opts.token) {
|
|
57
|
+
newConfig.token = opts.token;
|
|
58
|
+
}
|
|
59
|
+
writeFileSync(p, JSON.stringify(newConfig, null, 2) + "\n");
|
|
47
60
|
console.log(`Linked to ${server} (brain: ${opts.brain}).`);
|
|
48
|
-
console.log(`Config in .aidimag/config.json (
|
|
49
|
-
if (!opts.token && !getToken(server)) {
|
|
50
|
-
console.log("⚠ No token stored yet — pass --token or set AIDIMAG_API_KEY before
|
|
61
|
+
console.log(`Config stored in .aidimag/config.json (per-project).`);
|
|
62
|
+
if (!opts.token && !getToken(server, root)) {
|
|
63
|
+
console.log("⚠ No token stored yet — pass --token or set AIDIMAG_API_KEY before \`dim sync\`.");
|
|
64
|
+
}
|
|
65
|
+
else if (opts.token) {
|
|
66
|
+
console.log(`✓ Token stored in .aidimag/config.json`);
|
|
67
|
+
console.log(`⚠ Add .aidimag/config.json to .gitignore if you don't want to commit the token.`);
|
|
51
68
|
}
|
|
52
69
|
break;
|
|
53
70
|
}
|
|
@@ -60,8 +77,10 @@ export function registerSyncCommands(program) {
|
|
|
60
77
|
const cfg = readCloudConfig(root);
|
|
61
78
|
if (!cfg)
|
|
62
79
|
console.log("Not cloud-linked. Use `dim cloud link`.");
|
|
63
|
-
else
|
|
64
|
-
|
|
80
|
+
else {
|
|
81
|
+
const token = getToken(cfg.server, root);
|
|
82
|
+
console.log(`server: ${cfg.server}\nbrain: ${cfg.brain}\ntoken: ${token ? "stored in .aidimag/config.json" : "MISSING"}`);
|
|
83
|
+
}
|
|
65
84
|
break;
|
|
66
85
|
}
|
|
67
86
|
case "remote": {
|
package/dist/sync/client.d.ts
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* push: rows changed since last push (+ tombstones) → server
|
|
6
6
|
* pull: latest remote rows since cursor → apply if remote.updatedAt > local
|
|
7
7
|
*
|
|
8
|
-
* Config
|
|
9
|
-
* .aidimag/config.json
|
|
10
|
-
*
|
|
8
|
+
* Config (per-project):
|
|
9
|
+
* .aidimag/config.json { server, brain, token } — per-project, add to .gitignore if token is sensitive
|
|
10
|
+
* AIDIMAG_API_KEY env var — alternative to storing token in config
|
|
11
11
|
*/
|
|
12
12
|
import type { MemoryStore } from "../db/store.js";
|
|
13
13
|
import type { RemoteSnapshot } from "./server.js";
|
|
@@ -20,7 +20,7 @@ export declare function syncMetaKey(base: string, brain: string): string;
|
|
|
20
20
|
export declare function configPath(repoRoot: string): string;
|
|
21
21
|
export declare function readCloudConfig(repoRoot: string): CloudConfig | null;
|
|
22
22
|
export declare function writeCloudConfig(repoRoot: string, cfg: CloudConfig): void;
|
|
23
|
-
export declare function getToken(server: string): string | null;
|
|
23
|
+
export declare function getToken(server: string, repoRoot?: string): string | null;
|
|
24
24
|
export declare function saveToken(server: string, token: string): void;
|
|
25
25
|
export declare function removeToken(server: string): boolean;
|
|
26
26
|
export interface DeviceStart {
|
package/dist/sync/client.js
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* push: rows changed since last push (+ tombstones) → server
|
|
6
6
|
* pull: latest remote rows since cursor → apply if remote.updatedAt > local
|
|
7
7
|
*
|
|
8
|
-
* Config
|
|
9
|
-
* .aidimag/config.json
|
|
10
|
-
*
|
|
8
|
+
* Config (per-project):
|
|
9
|
+
* .aidimag/config.json { server, brain, token } — per-project, add to .gitignore if token is sensitive
|
|
10
|
+
* AIDIMAG_API_KEY env var — alternative to storing token in config
|
|
11
11
|
*/
|
|
12
12
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from "node:fs";
|
|
13
13
|
import { homedir } from "node:os";
|
|
@@ -55,18 +55,24 @@ export function writeCloudConfig(repoRoot, cfg) {
|
|
|
55
55
|
function credentialsPath() {
|
|
56
56
|
return path.join(homedir(), ".aidimag", "credentials.json");
|
|
57
57
|
}
|
|
58
|
-
export function getToken(server) {
|
|
58
|
+
export function getToken(server, repoRoot) {
|
|
59
59
|
if (process.env.AIDIMAG_API_KEY)
|
|
60
60
|
return process.env.AIDIMAG_API_KEY;
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
61
|
+
// Always use project-level config
|
|
62
|
+
if (repoRoot) {
|
|
63
|
+
const projectConfigPath = configPath(repoRoot);
|
|
64
|
+
if (existsSync(projectConfigPath)) {
|
|
65
|
+
try {
|
|
66
|
+
const cfg = JSON.parse(readFileSync(projectConfigPath, "utf8"));
|
|
67
|
+
if (cfg.token)
|
|
68
|
+
return cfg.token;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// ignore
|
|
72
|
+
}
|
|
73
|
+
}
|
|
69
74
|
}
|
|
75
|
+
return null;
|
|
70
76
|
}
|
|
71
77
|
export function saveToken(server, token) {
|
|
72
78
|
const p = credentialsPath();
|
|
@@ -162,7 +168,7 @@ export async function fetchRemoteSnapshot(repoRoot, opts = {}) {
|
|
|
162
168
|
const cfg = readCloudConfig(repoRoot);
|
|
163
169
|
if (!cfg)
|
|
164
170
|
throw new Error("repo is not cloud-linked. Run `dim cloud link --server <url> --brain <name> --token <token>` first.");
|
|
165
|
-
const token = getToken(cfg.server);
|
|
171
|
+
const token = getToken(cfg.server, repoRoot);
|
|
166
172
|
if (!token)
|
|
167
173
|
throw new Error(`no credentials for ${cfg.server}. Run \`dim cloud link\` with --token, or set AIDIMAG_API_KEY.`);
|
|
168
174
|
const q = new URLSearchParams({ brain: cfg.brain });
|
|
@@ -203,7 +209,7 @@ export async function sync(store, repoRoot, opts = {}) {
|
|
|
203
209
|
const cfg = readCloudConfig(repoRoot);
|
|
204
210
|
if (!cfg)
|
|
205
211
|
throw new Error("repo is not cloud-linked. Run `dim cloud link --server <url> --brain <name> --token <token>` first.");
|
|
206
|
-
const token = getToken(cfg.server);
|
|
212
|
+
const token = getToken(cfg.server, repoRoot);
|
|
207
213
|
if (!token)
|
|
208
214
|
throw new Error(`no credentials for ${cfg.server}. Run \`dim cloud link\` with --token, or set AIDIMAG_API_KEY.`);
|
|
209
215
|
const cursorKey = syncMetaKey(CURSOR_KEY, cfg.brain);
|