kodingo-cli 1.0.23 → 1.0.25

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.js CHANGED
@@ -18,6 +18,9 @@ const init_1 = require("./commands/init");
18
18
  const install_hook_1 = require("./commands/install-hook");
19
19
  const update_1 = require("./commands/update");
20
20
  const sync_1 = require("./commands/sync");
21
+ const context_1 = require("./commands/context");
22
+ const guardrails_1 = require("./commands/guardrails");
23
+ const session_brief_1 = require("./commands/session-brief");
21
24
  const aging_1 = require("./commands/aging");
22
25
  const program = new commander_1.Command();
23
26
  program.name("kodingo").description("Kodingo CLI").version("1.0.4");
@@ -226,4 +229,22 @@ program
226
229
  payload.repo = String(options.repo);
227
230
  await (0, scan_repo_1.scanRepoCommand)(payload);
228
231
  });
232
+ program
233
+ .command("context")
234
+ .description("Get affirmed memories for a file — designed for AI agents")
235
+ .requiredOption("-f, --file <path>", "File path to get context for")
236
+ .option("--prompt", "Output as prompt-ready string instead of JSON")
237
+ .option("--limit <n>", "Max memories to return", "20")
238
+ .action((opts) => (0, context_1.contextCommand)(opts.file, { prompt: opts.prompt, limit: parseInt(opts.limit) }));
239
+ program
240
+ .command("guardrails")
241
+ .description("Get project guardrails — rules and rejected patterns for AI agents")
242
+ .option("--prompt", "Output as prompt-ready string instead of JSON")
243
+ .action((opts) => (0, guardrails_1.guardrailsCommand)({ prompt: opts.prompt }));
244
+ program
245
+ .command("session-brief")
246
+ .description("Get a compact project intelligence brief — call at the start of an AI coding session")
247
+ .option("--prompt", "Output as prompt-ready string instead of JSON")
248
+ .option("--limit <n>", "Max memories to include", "30")
249
+ .action((opts) => (0, session_brief_1.sessionBriefCommand)({ prompt: opts.prompt, limit: parseInt(opts.limit) }));
229
250
  program.parse(process.argv);
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.contextCommand = contextCommand;
37
+ /**
38
+ * kodingo context --file <path>
39
+ *
40
+ * Returns all affirmed memories relevant to a file.
41
+ * Designed for AI agents — call before touching a file.
42
+ * Output: JSON by default, prompt-ready string with --prompt flag.
43
+ */
44
+ const path = __importStar(require("path"));
45
+ const persistence_config_1 = require("../utils/persistence-config");
46
+ const API_BASE_DEFAULT = "https://kodingo-api.onrender.com";
47
+ function normalizePath(p) {
48
+ return p.replace(/\\\\/g, "/").toLowerCase();
49
+ }
50
+ function getCredentials() {
51
+ const config = (0, persistence_config_1.readConfig)();
52
+ const cwd = normalizePath(process.cwd());
53
+ const ws = (0, persistence_config_1.readWorkspaceConfig)(cwd);
54
+ const token = ws?.token ?? config.token ?? "";
55
+ const apiUrl = ws?.apiUrl ?? config.apiUrl ?? API_BASE_DEFAULT;
56
+ return { token, apiUrl };
57
+ }
58
+ async function contextCommand(filePath, options) {
59
+ const { token, apiUrl } = getCredentials();
60
+ if (!token) {
61
+ console.error("No token found. Run `kodingo init` first.");
62
+ process.exit(1);
63
+ }
64
+ const limit = options.limit ?? 20;
65
+ const repoName = path.basename(process.cwd());
66
+ const relFile = path.relative(process.cwd(), path.resolve(filePath));
67
+ try {
68
+ // Fetch memories for this file (by repo path)
69
+ const res = await fetch(`${apiUrl}/memory?repo=${encodeURIComponent(relFile)}&status=affirmed&limit=${limit}`, { headers: { "X-Kodingo-Token": token } });
70
+ if (!res.ok) {
71
+ console.error(`API error: ${res.status}`);
72
+ process.exit(1);
73
+ }
74
+ const data = await res.json();
75
+ const memories = data.memories ?? [];
76
+ if (!options.prompt) {
77
+ console.log(JSON.stringify({ file: relFile, repo: repoName, count: memories.length, memories }, null, 2));
78
+ return;
79
+ }
80
+ // Prompt-ready format
81
+ if (!memories.length) {
82
+ console.log(`No affirmed memories found for ${relFile}.`);
83
+ return;
84
+ }
85
+ const lines = [
86
+ `# Kortex context for ${relFile}`,
87
+ `# ${memories.length} affirmed decision${memories.length !== 1 ? "s" : ""} your team has made about this file:`,
88
+ "",
89
+ ];
90
+ for (const m of memories) {
91
+ lines.push(`## ${m.title ?? "Decision"}`);
92
+ lines.push(m.content);
93
+ if (m.symbol)
94
+ lines.push(`Symbol: ${m.symbol}`);
95
+ lines.push(`Confidence: ${(m.confidence * 100).toFixed(0)}%`);
96
+ lines.push("");
97
+ }
98
+ lines.push("# End of Kortex context. Respect these decisions in your changes.");
99
+ console.log(lines.join("\n"));
100
+ }
101
+ catch (err) {
102
+ console.error("Failed to fetch context:", err.message);
103
+ process.exit(1);
104
+ }
105
+ }
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.guardrailsCommand = guardrailsCommand;
4
+ const persistence_config_1 = require("../utils/persistence-config");
5
+ const API_BASE_DEFAULT = "https://kodingo-api.onrender.com";
6
+ function normalizePath(p) {
7
+ return p.replace(/\\\\/g, "/").toLowerCase();
8
+ }
9
+ function getCredentials() {
10
+ const config = (0, persistence_config_1.readConfig)();
11
+ const cwd = normalizePath(process.cwd());
12
+ const ws = (0, persistence_config_1.readWorkspaceConfig)(cwd);
13
+ const token = ws?.token ?? config.token ?? "";
14
+ const apiUrl = ws?.apiUrl ?? config.apiUrl ?? API_BASE_DEFAULT;
15
+ return { token, apiUrl };
16
+ }
17
+ async function guardrailsCommand(options) {
18
+ const { token, apiUrl } = getCredentials();
19
+ if (!token) {
20
+ console.error("No token found. Run `kodingo init` first.");
21
+ process.exit(1);
22
+ }
23
+ try {
24
+ // Fetch denied memories (things explicitly ruled out)
25
+ const [deniedRes, affiredRes] = await Promise.all([
26
+ fetch(`${apiUrl}/memory?status=denied&limit=50`, { headers: { "X-Kodingo-Token": token } }),
27
+ fetch(`${apiUrl}/memory?status=affirmed&limit=50`, { headers: { "X-Kodingo-Token": token } }),
28
+ ]);
29
+ const denied = deniedRes.ok ? (await deniedRes.json()).memories ?? [] : [];
30
+ const affirmed = affiredRes.ok ? (await affiredRes.json()).memories ?? [] : [];
31
+ // High confidence affirmed = guardrails (confidence >= 0.7)
32
+ const rules = affirmed.filter((m) => m.confidence >= 0.7);
33
+ if (!options.prompt) {
34
+ console.log(JSON.stringify({ rules: rules.length, denied: denied.length, rules_list: rules, denied_list: denied }, null, 2));
35
+ return;
36
+ }
37
+ const lines = ["# Kortex guardrails — decisions your team has enforced", ""];
38
+ if (rules.length) {
39
+ lines.push("## Rules to follow:");
40
+ for (const m of rules) {
41
+ lines.push(`- ${m.title ?? m.content.slice(0, 100)}`);
42
+ if (m.symbol)
43
+ lines.push(` (applies to: ${m.symbol})`);
44
+ }
45
+ lines.push("");
46
+ }
47
+ if (denied.length) {
48
+ lines.push("## Patterns explicitly rejected by your team (do NOT use):");
49
+ for (const m of denied) {
50
+ lines.push(`- ${m.title ?? m.content.slice(0, 100)}`);
51
+ if (m.symbol)
52
+ lines.push(` (rejected for: ${m.symbol})`);
53
+ }
54
+ lines.push("");
55
+ }
56
+ if (!rules.length && !denied.length) {
57
+ lines.push("No guardrails defined yet. Affirm and deny memories to build them.");
58
+ }
59
+ lines.push("# End of Kortex guardrails.");
60
+ console.log(lines.join("\n"));
61
+ }
62
+ catch (err) {
63
+ console.error("Failed to fetch guardrails:", err.message);
64
+ process.exit(1);
65
+ }
66
+ }
@@ -56,6 +56,20 @@ const API_BASE = "https://kodingo-api.onrender.com";
56
56
  const APP_URL = "https://kodingo.xyz";
57
57
  const CONFIG_DIR = path.join(os.homedir(), ".kodingo");
58
58
  const AUTH_TOKEN_PATH = path.join(CONFIG_DIR, "auth.json");
59
+ // ── Machine ID ────────────────────────────────────────────────────────────────
60
+ function generateMachineId() {
61
+ const raw = `${os.hostname()}::${os.userInfo().username}::${process.platform}`;
62
+ return require("crypto").createHash("sha256").update(raw).digest("hex").slice(0, 32);
63
+ }
64
+ function getMachineId() {
65
+ const config = (0, persistence_config_1.readConfig)();
66
+ if (config.machineId)
67
+ return config.machineId;
68
+ const machineId = generateMachineId();
69
+ const existing = (0, persistence_config_1.readConfig)();
70
+ (0, persistence_config_1.writeConfig)({ ...existing, machineId });
71
+ return machineId;
72
+ }
59
73
  // ── Auth token storage ────────────────────────────────────────────────────────
60
74
  function readAuthToken() {
61
75
  try {
@@ -255,7 +269,8 @@ function registerInitCommand(program) {
255
269
  const apiUrl = API_BASE;
256
270
  // preserve existing workspaces, never overwrite global token
257
271
  const existingConfig = (0, persistence_config_1.readConfig)();
258
- (0, persistence_config_1.writeConfig)({ ...existingConfig, mode: "cloud", apiUrl });
272
+ const machineId = getMachineId();
273
+ (0, persistence_config_1.writeConfig)({ ...existingConfig, mode: "cloud", apiUrl, machineId });
259
274
  (0, persistence_config_1.writeWorkspaceConfig)(repoRoot, { mode: "cloud", apiUrl, token: selectedProject.token });
260
275
  ensureGitignoreEntry(repoRoot, ".kortex/");
261
276
  console.log(`✔ Connected. Token saved to ${persistence_config_1.CONFIG_PATH}`);
@@ -38,7 +38,7 @@ const IGNORED_DIRS = [
38
38
  "node_modules", ".git", ".kortex", "dist", "build",
39
39
  "out", ".next", "coverage", "__pycache__", "vendor",
40
40
  ];
41
- const MAX_SYMBOLS = 50;
41
+ const MAX_SYMBOLS = 200;
42
42
  const BATCH_SIZE = 5;
43
43
  const BATCH_DELAY_MS = 1200;
44
44
  function findRepoRoot(startPath) {
@@ -107,8 +107,12 @@ async function fetchExistingSymbols(token, repo) {
107
107
  break;
108
108
  const data = await res.json();
109
109
  for (const m of data.memories ?? []) {
110
- if (m.symbol)
110
+ if (m.symbol) {
111
+ // Store both symbol-only and symbol::repo keys for accurate matching
111
112
  known.add(m.symbol);
113
+ if (m.repo)
114
+ known.add(`${m.symbol}::${m.repo}`);
115
+ }
112
116
  }
113
117
  offset += limit;
114
118
  if (offset >= (data.total ?? 0))
@@ -195,7 +199,9 @@ async function scanRepoCommand(options = {}) {
195
199
  if (seen.has(key))
196
200
  continue;
197
201
  seen.add(key);
198
- if (!existingSymbols.has(sym.name))
202
+ const symRepoKey = `${sym.name}::${path_1.default.basename(sym.file)}`;
203
+ const hasMemory = existingSymbols.has(symRepoKey) || existingSymbols.has(sym.name);
204
+ if (!hasMemory)
199
205
  toCapture.push(sym);
200
206
  }
201
207
  if (toCapture.length === 0) {
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.sessionBriefCommand = sessionBriefCommand;
37
+ /**
38
+ * kodingo session-brief
39
+ *
40
+ * Returns a compact summary of the most important decisions across the project.
41
+ * Designed for AI agents — call once at the start of a new coding session.
42
+ * Output: JSON by default, prompt-ready string with --prompt flag.
43
+ */
44
+ const persistence_config_1 = require("../utils/persistence-config");
45
+ const path = __importStar(require("path"));
46
+ const API_BASE_DEFAULT = "https://kodingo-api.onrender.com";
47
+ function normalizePath(p) {
48
+ return p.replace(/\\\\/g, "/").toLowerCase();
49
+ }
50
+ function getCredentials() {
51
+ const config = (0, persistence_config_1.readConfig)();
52
+ const cwd = normalizePath(process.cwd());
53
+ const ws = (0, persistence_config_1.readWorkspaceConfig)(cwd);
54
+ const token = ws?.token ?? config.token ?? "";
55
+ const apiUrl = ws?.apiUrl ?? config.apiUrl ?? API_BASE_DEFAULT;
56
+ return { token, apiUrl };
57
+ }
58
+ async function sessionBriefCommand(options) {
59
+ const { token, apiUrl } = getCredentials();
60
+ if (!token) {
61
+ console.error("No token found. Run `kodingo init` first.");
62
+ process.exit(1);
63
+ }
64
+ const limit = options.limit ?? 30;
65
+ const repoName = path.basename(process.cwd());
66
+ try {
67
+ // Top affirmed memories sorted by confidence
68
+ const res = await fetch(`${apiUrl}/memory?status=affirmed&limit=${limit}`, { headers: { "X-Kodingo-Token": token } });
69
+ if (!res.ok) {
70
+ console.error(`API error: ${res.status}`);
71
+ process.exit(1);
72
+ }
73
+ const data = await res.json();
74
+ const memories = (data.memories ?? []).sort((a, b) => b.confidence - a.confidence);
75
+ if (!options.prompt) {
76
+ console.log(JSON.stringify({
77
+ repo: repoName,
78
+ total_affirmed: data.total,
79
+ showing: memories.length,
80
+ memories,
81
+ }, null, 2));
82
+ return;
83
+ }
84
+ const lines = [
85
+ `# Kortex session brief for ${repoName}`,
86
+ `# ${data.total} total affirmed decisions. Showing top ${memories.length} by confidence.`,
87
+ `# Read these before writing any code.`,
88
+ "",
89
+ ];
90
+ // Group by type
91
+ const byType = {};
92
+ for (const m of memories) {
93
+ const t = m.type ?? "context";
94
+ if (!byType[t])
95
+ byType[t] = [];
96
+ byType[t].push(m);
97
+ }
98
+ for (const [type, items] of Object.entries(byType)) {
99
+ lines.push(`## ${type.charAt(0).toUpperCase() + type.slice(1)} decisions`);
100
+ for (const m of items) {
101
+ const conf = (m.confidence * 100).toFixed(0);
102
+ const symbol = m.symbol ? ` [${m.symbol}]` : "";
103
+ lines.push(`- ${m.title ?? m.content.slice(0, 100)}${symbol} (${conf}% confidence)`);
104
+ }
105
+ lines.push("");
106
+ }
107
+ lines.push("# End of Kortex session brief. These decisions represent your team\'s collective intelligence.");
108
+ console.log(lines.join("\n"));
109
+ }
110
+ catch (err) {
111
+ console.error("Failed to fetch session brief:", err.message);
112
+ process.exit(1);
113
+ }
114
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kodingo-cli",
3
- "version": "1.0.23",
3
+ "version": "1.0.25",
4
4
  "description": "Kodingo CLI",
5
5
  "license": "MIT",
6
6
  "private": false,