qlogicagent 2.2.0 → 2.3.0

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,7 +1,14 @@
1
1
  /**
2
2
  * Skill self-learning: decides whether a completed turn should
3
3
  * trigger skill creation or improvement instructions.
4
+ *
5
+ * Guards against proliferation:
6
+ * - MAX_SKILLS_PER_PROJECT: hard cap on project-level skills
7
+ * - Dedup check: compares tool-set signature against existing skills
8
+ * - Cooldown: prevents rapid-fire creation within a session
4
9
  */
10
+ import { MAX_SKILLS_PER_PROJECT, MAX_SKILLS_GLOBAL } from "../agent/tunable-defaults.js";
11
+ export { MAX_SKILLS_PER_PROJECT, MAX_SKILLS_GLOBAL };
5
12
  export interface SkillTurnResult {
6
13
  ok: boolean;
7
14
  /** Number of tool invocations in this turn */
@@ -36,6 +43,32 @@ export interface SkillImproveInstruction {
36
43
  reason: string;
37
44
  }
38
45
  export type SkillInstruction = SkillCreateInstruction | SkillImproveInstruction;
46
+ /**
47
+ * Reset cooldown state (for testing).
48
+ */
49
+ export declare function resetSkillCreationCooldown(): void;
50
+ /**
51
+ * Check if an existing skill in skillsDir already covers the same tool set.
52
+ * Returns the name of the conflicting skill, or null if none found.
53
+ */
54
+ export declare function findDuplicateSkill(tools: string[], skillsDir: string): string | null;
55
+ /**
56
+ * Count active skills in a directory.
57
+ */
58
+ export declare function countSkillsInDir(skillsDir: string): number;
59
+ /**
60
+ * Context for proliferation checks.
61
+ */
62
+ export interface SkillCreationContext {
63
+ /** Project-level skills directory */
64
+ projectSkillsDir?: string;
65
+ /** User-level (global) skills directory */
66
+ globalSkillsDir?: string;
67
+ /** Tool names used in this turn */
68
+ tools: string[];
69
+ /** Optional suggested name */
70
+ suggestedName?: string;
71
+ }
39
72
  /**
40
73
  * Determine whether a completed turn should produce a skill instruction.
41
74
  *
@@ -44,16 +77,14 @@ export type SkillInstruction = SkillCreateInstruction | SkillImproveInstruction;
44
77
  * - It involved multi-step orchestration
45
78
  * - It used ≥3 tool calls across ≥2 distinct tools
46
79
  * - No existing skill was already applied
47
- *
48
- * An improvement is suggested when:
49
- * - The turn used an existing skill but got negative feedback
80
+ * - Cooldown has elapsed since last skill creation
81
+ * - No duplicate skill exists (same tool signature)
82
+ * - Project skill count < MAX_SKILLS_PER_PROJECT
50
83
  */
51
- export declare function shouldCreateSkill(result: SkillTurnResult): boolean;
84
+ export declare function shouldCreateSkill(result: SkillTurnResult, context?: SkillCreationContext): boolean;
52
85
  export declare function shouldImproveSkill(result: SkillTurnResult): boolean;
53
86
  /**
54
87
  * Build a skill instruction from a turn result, or null if none is warranted.
88
+ * Updates cooldown timestamp on success.
55
89
  */
56
- export declare function buildSkillInstruction(result: SkillTurnResult, context: {
57
- tools: string[];
58
- suggestedName?: string;
59
- }): SkillInstruction | null;
90
+ export declare function buildSkillInstruction(result: SkillTurnResult, context: SkillCreationContext): SkillInstruction | null;
@@ -9,12 +9,12 @@
9
9
  * 5. Depth control via in-memory counter (not DB-based)
10
10
  */
11
11
  import type { AgentDefinition } from "./agent-registry.js";
12
+ import { MAX_FORK_DEPTH } from "../../agent/tunable-defaults.js";
12
13
  /** Sentinel tag injected into fork children to prevent recursive forking. */
13
14
  export declare const FORK_SENTINEL_TAG = "<fork-child-context>";
14
15
  /** Placeholder text used for all tool_results in shared prefix (ensures byte-identical prefix). */
15
16
  export declare const FORK_PLACEHOLDER_RESULT = "Fork started \u2014 processing in background";
16
- /** Maximum fork depth for in-memory agents (CC: MAX_FORK_DEPTH). */
17
- export declare const MAX_FORK_DEPTH = 4;
17
+ export { MAX_FORK_DEPTH };
18
18
  export interface ForkContext {
19
19
  /** Parent's full message history (becomes shared prefix for cache). */
20
20
  parentMessages: unknown[];
@@ -444,6 +444,22 @@ export interface ProjectSwitchedNotification {
444
444
  export interface ProjectDeletedNotification {
445
445
  id: string;
446
446
  }
447
+ /** A project was renamed. */
448
+ export interface ProjectRenamedNotification {
449
+ id: string;
450
+ name: string;
451
+ workspaceDir: string;
452
+ }
453
+ /** A project was archived. */
454
+ export interface ProjectArchivedNotification {
455
+ id: string;
456
+ }
457
+ /** A project was unarchived (restored). */
458
+ export interface ProjectUnarchivedNotification {
459
+ id: string;
460
+ name: string;
461
+ workspaceDir: string;
462
+ }
447
463
  export interface NotificationMethodMap {
448
464
  "turn.start": TurnStartNotification;
449
465
  "turn.delta": TurnDeltaNotification;
@@ -495,6 +511,9 @@ export interface NotificationMethodMap {
495
511
  "project.created": ProjectCreatedNotification;
496
512
  "project.switched": ProjectSwitchedNotification;
497
513
  "project.deleted": ProjectDeletedNotification;
514
+ "project.renamed": ProjectRenamedNotification;
515
+ "project.archived": ProjectArchivedNotification;
516
+ "project.unarchived": ProjectUnarchivedNotification;
498
517
  }
499
518
  /** All known notification method names. */
500
519
  export type NotificationMethod = keyof NotificationMethodMap;
@@ -2,11 +2,8 @@ import type { HookRegistry } from "../../contracts/hooks.js";
2
2
  import type { MemoryProvider } from "qlogicagent-runtime-contracts";
3
3
  import type { Memdir } from "../../skills/memory/memdir.js";
4
4
  export declare const MEMORY_PREFETCH_CONFIG: {
5
- /** Max bytes of memory content to inject per session (CC: 60KB) */
6
5
  readonly MAX_SESSION_BYTES: number;
7
- /** Max results per recall query */
8
6
  readonly LIMIT_PER_RECALL: 10;
9
- /** Max entries in surfaced-path LRU set */
10
7
  readonly MAX_SURFACED_ENTRIES: 100;
11
8
  };
12
9
  export interface MemoryHooksDeps {
@@ -1,14 +1,12 @@
1
1
  import type { HookRegistry } from "../../contracts/hooks.js";
2
2
  export declare const SKILL_RECALL_CONFIG: {
3
- /** Max number of cross-project skills to inject per turn. */
4
3
  readonly MAX_RECALLED_SKILLS: 3;
5
- /** Max chars of skill content to include in recall context. */
6
4
  readonly MAX_SKILL_CONTENT_CHARS: 800;
7
- /** Cache TTL for known project skill index (ms). */
8
5
  readonly CACHE_TTL_MS: number;
9
6
  };
10
7
  /**
11
- * Detect whether user message contains retrospective/cross-reference semantics.
8
+ * Detect whether user message contains retrospective/cross-reference semantics
9
+ * OR similar-task patterns that could benefit from existing skills.
12
10
  * Returns extracted keywords for skill matching if triggered, or null.
13
11
  */
14
12
  export declare function detectRetrospectiveTrigger(message: string): string[] | null;
@@ -22,6 +22,12 @@ export declare function deleteProject(projectId: string): {
22
22
  switchedTo?: ProjectInfo;
23
23
  };
24
24
  export declare function getOrCreateDefaultProject(defaultWorkspaceDir: string): ProjectInfo;
25
+ export declare function renameProject(projectId: string, newName: string): ProjectInfo | null;
26
+ export declare function archiveProject(projectId: string): {
27
+ archived: boolean;
28
+ switchedTo?: ProjectInfo;
29
+ };
30
+ export declare function unarchiveProject(projectId: string): ProjectInfo | null;
25
31
  export declare function findByGroupId(groupId: string): ProjectInfo | null;
26
32
  export declare function archiveByGroupId(groupId: string): {
27
33
  archived: boolean;
@@ -9,8 +9,11 @@
9
9
  *
10
10
  * 2. **First-message prompt injection**: For agents without native skill
11
11
  * directory support, prepend skill instructions text to the first prompt.
12
+ * Subject to a token budget to prevent context bloat.
12
13
  */
13
14
  import type { AgentCapabilities } from "./acp-types.js";
15
+ import { SKILL_INJECTION_MAX_CHARS, SKILL_INJECTION_MAX_COUNT } from "../../agent/tunable-defaults.js";
16
+ export { SKILL_INJECTION_MAX_CHARS, SKILL_INJECTION_MAX_COUNT };
14
17
  export declare class SkillInjector {
15
18
  /**
16
19
  * Synchronize skills to an agent's native skill directory.
@@ -24,6 +27,9 @@ export declare class SkillInjector {
24
27
  * Build a skill description block to prepend to the first message
25
28
  * for agents that don't support native skill directories.
26
29
  *
30
+ * Respects SKILL_INJECTION_MAX_CHARS and SKILL_INJECTION_MAX_COUNT
31
+ * to prevent token bloat.
32
+ *
27
33
  * @param cwd - Project working directory (for project-level skills)
28
34
  * @returns Markdown text with skill instructions, or empty string if no skills.
29
35
  */
@@ -44,8 +50,9 @@ export declare class SkillInjector {
44
50
  */
45
51
  applySkills(capabilities?: AgentCapabilities, cwd?: string): string;
46
52
  /**
47
- * Collect all skill file paths from user-level and project-level dirs.
48
- * Only `.md` files are treated as skills.
53
+ * Collect all skill file paths from project-level and user-level dirs.
54
+ * Skills are stored as `<dir>/<skillName>/SKILL.md`.
55
+ * Priority: project > global (project listed first for budget-constrained injection).
49
56
  */
50
57
  private collectSkillPaths;
51
58
  }
@@ -60,6 +60,33 @@ export interface SkillStorageDeps {
60
60
  /** Write the registry lock file. */
61
61
  writeLockfile(lockfile: SkillLockfile): Promise<void>;
62
62
  }
63
+ /**
64
+ * A single version history entry for a skill.
65
+ */
66
+ export interface SkillVersionEntry {
67
+ version: string;
68
+ updatedAt: string;
69
+ changelog?: string;
70
+ /** Integrity hash of the SKILL.md content at this version (sha256). */
71
+ integrity?: string;
72
+ }
73
+ /**
74
+ * Usage statistics for a skill.
75
+ */
76
+ export interface SkillUsageStats {
77
+ /** Total number of times this skill has been invoked/applied. */
78
+ invokeCount: number;
79
+ /** Number of turns where the skill was active and contributed. */
80
+ activeCount: number;
81
+ /** Number of times the skill received positive feedback. */
82
+ positiveCount: number;
83
+ /** Number of times the skill received negative feedback. */
84
+ negativeCount: number;
85
+ /** ISO 8601 timestamp of last use. */
86
+ lastUsedAt?: string;
87
+ /** Derived success rate = (invokeCount - negativeCount) / invokeCount */
88
+ successRate?: number;
89
+ }
63
90
  /**
64
91
  * Single entry in the skill lockfile.
65
92
  */
@@ -71,6 +98,12 @@ export interface SkillLockEntry {
71
98
  scanSummary?: SkillScanSummary;
72
99
  /** Integrity hash of the SKILL.md content (sha256). */
73
100
  integrity?: string;
101
+ /** Current version (from frontmatter or auto-incremented). */
102
+ currentVersion?: string;
103
+ /** Version history — newest first. */
104
+ versionHistory?: SkillVersionEntry[];
105
+ /** Usage statistics. */
106
+ usage?: SkillUsageStats;
74
107
  }
75
108
  /**
76
109
  * Complete lockfile for all installed skills.
@@ -79,6 +112,38 @@ export interface SkillLockfile {
79
112
  version: 1;
80
113
  entries: Record<string, SkillLockEntry>;
81
114
  }
115
+ /**
116
+ * Record a skill usage event. Mutates the lockfile entry in-place.
117
+ */
118
+ export declare function recordSkillUsage(lockfile: SkillLockfile, skillName: string, feedback?: "positive" | "negative" | null): void;
119
+ /**
120
+ * Record a skill version update. Pushes current version to history.
121
+ */
122
+ export declare function recordSkillVersionUpdate(lockfile: SkillLockfile, skillName: string, newVersion: string, changelog?: string, integrity?: string): void;
123
+ /**
124
+ * Lightweight per-skill stats stored in `~/.qlogicagent/skill-stats.json`.
125
+ * This is independent of the lockfile — covers learned, promoted, and installed skills.
126
+ */
127
+ export interface SkillStatsFile {
128
+ [skillName: string]: SkillUsageStats;
129
+ }
130
+ /**
131
+ * Record a skill invocation. Fire-and-forget — never throws.
132
+ * @param agentHome - path to `~/.qlogicagent/`
133
+ * @param skillName - the skill that was invoked
134
+ * @param success - whether the invocation completed without error
135
+ */
136
+ export declare function trackSkillInvocation(agentHome: string, skillName: string, success: boolean): void;
137
+ /**
138
+ * Read stats for a skill. Returns undefined if no stats recorded.
139
+ */
140
+ export declare function getSkillStats(agentHome: string, skillName: string): SkillUsageStats | undefined;
141
+ /**
142
+ * Get all skill stats. Useful for UI display.
143
+ */
144
+ export declare function getAllSkillStats(agentHome: string): SkillStatsFile;
145
+ /** Reset cache (for testing). */
146
+ export declare function resetStatsCache(): void;
82
147
  /**
83
148
  * Result of a skill install operation.
84
149
  */
@@ -89,6 +89,8 @@ export declare class AcpServer {
89
89
  private activeSessionId;
90
90
  /** Pending permission requests (agent → host) waiting for response */
91
91
  private pendingPermissions;
92
+ /** Map from outbound JSON-RPC request id → permissionId for response matching */
93
+ private outboundRequestMap;
92
94
  constructor(transport: Transport, handler: AcpRequestHandler, config?: AcpServerConfig);
93
95
  /**
94
96
  * Route an incoming raw message through ACP protocol handling.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qlogicagent",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "XiaozhiClaw Agent CLI — subprocess architecture (JSON-RPC over stdio)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",