tuna-agent 0.1.55 → 0.1.56

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.
@@ -32,6 +32,7 @@ export declare class ClaudeCodeAdapter implements AgentAdapter {
32
32
  private static readonly PATTERN_CHECK_INTERVAL;
33
33
  private metricsMap;
34
34
  private learnedRulesMap;
35
+ private agentFolderMap;
35
36
  private currentAgentId;
36
37
  /** Folder basename of current agent (e.g. "co-founder"). Used as Mem0 user_id. */
37
38
  private currentAgentName;
@@ -40,6 +41,8 @@ export declare class ClaudeCodeAdapter implements AgentAdapter {
40
41
  constructor(config: AgentConfig);
41
42
  /** Get all per-agent metrics for heartbeat. */
42
43
  getMetrics(): Record<string, unknown>;
44
+ /** Register an agent folder path for rules parsing (called from daemon). */
45
+ registerAgentFolder(agentId: string, folderPath: string): void;
43
46
  checkHealth(): Promise<{
44
47
  ok: boolean;
45
48
  message: string;
@@ -17,6 +17,7 @@ export class ClaudeCodeAdapter {
17
17
  // Per-agent state (one daemon handles multiple agents)
18
18
  metricsMap = new Map();
19
19
  learnedRulesMap = new Map();
20
+ agentFolderMap = new Map(); // agentId -> folder path
20
21
  currentAgentId = '';
21
22
  /** Folder basename of current agent (e.g. "co-founder"). Used as Mem0 user_id. */
22
23
  currentAgentName = '';
@@ -48,6 +49,13 @@ export class ClaudeCodeAdapter {
48
49
  }
49
50
  /** Get all per-agent metrics for heartbeat. */
50
51
  getMetrics() {
52
+ // Re-parse rules from CLAUDE.md for all known agents
53
+ this.agentFolderMap.forEach((folder, agentId) => {
54
+ const savedId = this.currentAgentId;
55
+ this.currentAgentId = agentId;
56
+ this.parseLearnedRules(path.join(folder, 'CLAUDE.md'));
57
+ this.currentAgentId = savedId;
58
+ });
51
59
  const agentMetricsMap = {};
52
60
  this.metricsMap.forEach((m, agentId) => {
53
61
  const entry = { ...m };
@@ -59,6 +67,10 @@ export class ClaudeCodeAdapter {
59
67
  });
60
68
  return { agentMetricsMap };
61
69
  }
70
+ /** Register an agent folder path for rules parsing (called from daemon). */
71
+ registerAgentFolder(agentId, folderPath) {
72
+ this.agentFolderMap.set(agentId, folderPath);
73
+ }
62
74
  async checkHealth() {
63
75
  try {
64
76
  execSync('which claude', { stdio: 'ignore' });
@@ -97,11 +109,9 @@ export class ClaudeCodeAdapter {
97
109
  this.currentAgentId = task.agentId || '';
98
110
  const defaultWorkspaceEarly = path.join(os.homedir(), 'tuna-workspace');
99
111
  this.currentAgentName = path.basename(task.repoPath || defaultWorkspaceEarly);
100
- // Parse existing learned rules on first task (sync to API on next heartbeat)
101
- if (!this.learnedRulesMap.has(this.currentAgentId)) {
102
- const cwd = task.repoPath || defaultWorkspaceEarly;
103
- this.parseLearnedRules(path.join(cwd, 'CLAUDE.md'));
104
- }
112
+ // Track agent folder for rules parsing in heartbeat
113
+ const cwd = task.repoPath || defaultWorkspaceEarly;
114
+ this.agentFolderMap.set(this.currentAgentId, cwd);
105
115
  if (task.mode !== 'tuna') {
106
116
  console.log(`[ClaudeCode] Agent Team mode — direct chat with Claude CLI`);
107
117
  ws.sendProgress(task.id, 'executing', { startedAt: new Date().toISOString() });
@@ -885,20 +895,35 @@ export class ClaudeCodeAdapter {
885
895
  const rulesText = nextSection !== -1 ? sectionContent.substring(0, nextSection) : sectionContent;
886
896
  const rules = [];
887
897
  const ruleRegex = /^- (.+?)(?:\s*\(confidence:\s*([\d.]+)\))?$/;
898
+ // First pass: collect raw confidence values
899
+ const rawEntries = [];
888
900
  for (const line of rulesText.split('\n')) {
889
901
  const trimmed = line.trim();
890
902
  if (!trimmed || !trimmed.startsWith('-'))
891
903
  continue;
892
904
  const match = ruleRegex.exec(trimmed);
893
905
  if (match) {
894
- rules.push({
906
+ rawEntries.push({
895
907
  content: match[1].trim(),
896
- confidence: match[2] ? parseFloat(match[2]) : 0.3,
897
- sourceCount: 1,
898
- createdAt: new Date().toISOString(),
908
+ rawConf: match[2] ? parseFloat(match[2]) : 0.3,
899
909
  });
900
910
  }
901
911
  }
912
+ // Normalize confidence: if any value > 1, treat as source_count and scale to 0-1
913
+ const maxConf = Math.max(...rawEntries.map(e => e.rawConf), 1);
914
+ const needsNormalization = maxConf > 1;
915
+ for (const entry of rawEntries) {
916
+ const sourceCount = needsNormalization ? Math.round(entry.rawConf) : 1;
917
+ const confidence = needsNormalization
918
+ ? Math.min(Math.max(entry.rawConf / maxConf, 0.1), 1.0)
919
+ : entry.rawConf;
920
+ rules.push({
921
+ content: entry.content,
922
+ confidence: Math.round(confidence * 100) / 100,
923
+ sourceCount,
924
+ createdAt: new Date().toISOString(),
925
+ });
926
+ }
902
927
  if (rules.length > 0) {
903
928
  this.learnedRulesMap.set(this.currentAgentId, rules);
904
929
  this.metrics.rulesCount = rules.length;
@@ -264,6 +264,10 @@ export async function startDaemon(config) {
264
264
  ? path.join(os.homedir(), rawFolder.slice(1))
265
265
  : rawFolder;
266
266
  console.log(`[Daemon] Rescan skills for agent ${agentId}, folder: ${folder || '(none)'}`);
267
+ // Register folder for rules parsing in heartbeat
268
+ if (folder && agentId && adapter.type === 'claude-code') {
269
+ adapter.registerAgentFolder(agentId, folder);
270
+ }
267
271
  const folders = folder ? [folder] : [];
268
272
  const skills = scanSkills(wsPath, folders);
269
273
  ws.send({ action: 'agent_skills_scanned', agent_id: agentId, skills });
@@ -297,6 +301,10 @@ export async function startDaemon(config) {
297
301
  else {
298
302
  console.log(`[Daemon] .claude/CLAUDE.md already exists, skipping`);
299
303
  }
304
+ // Register folder for rules parsing in heartbeat
305
+ if (adapter.type === 'claude-code') {
306
+ adapter.registerAgentFolder(agentId, folderPath);
307
+ }
300
308
  ws.send({ action: 'agent_folder_created', agent_id: agentId, success: true });
301
309
  console.log(`[Daemon] Agent folder created: ${folderPath}`);
302
310
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tuna-agent",
3
- "version": "0.1.55",
3
+ "version": "0.1.56",
4
4
  "description": "Tuna Agent - Run AI coding tasks on your machine",
5
5
  "bin": {
6
6
  "tuna-agent": "dist/cli/index.js"