@phnx-labs/agents-cli 1.14.2 → 1.14.4

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.
Files changed (121) hide show
  1. package/README.md +17 -7
  2. package/dist/browser.d.ts +2 -0
  3. package/dist/browser.js +7 -0
  4. package/dist/commands/browser.d.ts +3 -0
  5. package/dist/commands/browser.js +392 -0
  6. package/dist/commands/daemon.js +1 -1
  7. package/dist/commands/doctor.d.ts +16 -9
  8. package/dist/commands/doctor.js +248 -12
  9. package/dist/commands/prune.js +9 -3
  10. package/dist/commands/refresh-rules.d.ts +15 -0
  11. package/dist/commands/{refresh-memory.js → refresh-rules.js} +14 -14
  12. package/dist/commands/routines.js +1 -1
  13. package/dist/commands/rules.js +100 -4
  14. package/dist/commands/secrets.js +198 -11
  15. package/dist/commands/sync.js +19 -0
  16. package/dist/commands/teams.js +184 -22
  17. package/dist/commands/trash.d.ts +10 -0
  18. package/dist/commands/trash.js +187 -0
  19. package/dist/commands/view.js +47 -14
  20. package/dist/index.js +62 -4
  21. package/dist/lib/agents.js +2 -2
  22. package/dist/lib/browser/cdp.d.ts +24 -0
  23. package/dist/lib/browser/cdp.js +94 -0
  24. package/dist/lib/browser/chrome.d.ts +16 -0
  25. package/dist/lib/browser/chrome.js +157 -0
  26. package/dist/lib/browser/drivers/local.d.ts +8 -0
  27. package/dist/lib/browser/drivers/local.js +22 -0
  28. package/dist/lib/browser/drivers/ssh.d.ts +9 -0
  29. package/dist/lib/browser/drivers/ssh.js +129 -0
  30. package/dist/lib/browser/index.d.ts +5 -0
  31. package/dist/lib/browser/index.js +5 -0
  32. package/dist/lib/browser/input.d.ts +6 -0
  33. package/dist/lib/browser/input.js +52 -0
  34. package/dist/lib/browser/ipc.d.ts +12 -0
  35. package/dist/lib/browser/ipc.js +223 -0
  36. package/dist/lib/browser/profiles.d.ts +11 -0
  37. package/dist/lib/browser/profiles.js +61 -0
  38. package/dist/lib/browser/refs.d.ts +21 -0
  39. package/dist/lib/browser/refs.js +88 -0
  40. package/dist/lib/browser/service.d.ts +45 -0
  41. package/dist/lib/browser/service.js +404 -0
  42. package/dist/lib/browser/types.d.ts +73 -0
  43. package/dist/lib/browser/types.js +7 -0
  44. package/dist/lib/cloud/codex.js +1 -1
  45. package/dist/lib/cloud/registry.js +2 -2
  46. package/dist/lib/cloud/rush.js +2 -2
  47. package/dist/lib/cloud/store.js +2 -2
  48. package/dist/lib/daemon.d.ts +1 -1
  49. package/dist/lib/daemon.js +47 -11
  50. package/dist/lib/diff-text.d.ts +25 -0
  51. package/dist/lib/diff-text.js +47 -0
  52. package/dist/lib/doctor-diff.d.ts +64 -0
  53. package/dist/lib/doctor-diff.js +497 -0
  54. package/dist/lib/git.js +3 -3
  55. package/dist/lib/hooks.d.ts +6 -0
  56. package/dist/lib/hooks.js +6 -1
  57. package/dist/lib/migrate.js +123 -0
  58. package/dist/lib/pty-client.js +3 -3
  59. package/dist/lib/pty-server.js +36 -7
  60. package/dist/lib/resources/commands.d.ts +46 -0
  61. package/dist/lib/resources/commands.js +208 -0
  62. package/dist/lib/resources/hooks.d.ts +12 -0
  63. package/dist/lib/resources/hooks.js +136 -0
  64. package/dist/lib/resources/index.d.ts +36 -0
  65. package/dist/lib/resources/index.js +69 -0
  66. package/dist/lib/resources/mcp.d.ts +34 -0
  67. package/dist/lib/resources/mcp.js +483 -0
  68. package/dist/lib/resources/permissions.d.ts +13 -0
  69. package/dist/lib/resources/permissions.js +184 -0
  70. package/dist/lib/resources/rules.d.ts +43 -0
  71. package/dist/lib/resources/rules.js +146 -0
  72. package/dist/lib/resources/skills.d.ts +37 -0
  73. package/dist/lib/resources/skills.js +238 -0
  74. package/dist/lib/resources/subagents.d.ts +46 -0
  75. package/dist/lib/resources/subagents.js +198 -0
  76. package/dist/lib/resources/types.d.ts +82 -0
  77. package/dist/lib/resources/types.js +8 -0
  78. package/dist/lib/resources.js +1 -1
  79. package/dist/lib/rotate.d.ts +8 -1
  80. package/dist/lib/rotate.js +17 -4
  81. package/dist/lib/rules/compile.d.ts +104 -0
  82. package/dist/lib/{memory-compile.js → rules/compile.js} +160 -21
  83. package/dist/lib/rules/compose.d.ts +78 -0
  84. package/dist/lib/rules/compose.js +170 -0
  85. package/dist/lib/{memory.d.ts → rules/rules.d.ts} +5 -5
  86. package/dist/lib/{memory.js → rules/rules.js} +10 -10
  87. package/dist/lib/secrets/AgentsKeychain.app/Contents/CodeResources +0 -0
  88. package/dist/lib/secrets/AgentsKeychain.app/Contents/MacOS/AgentsKeychain +0 -0
  89. package/dist/lib/secrets/bundles.d.ts +61 -4
  90. package/dist/lib/secrets/bundles.js +222 -54
  91. package/dist/lib/secrets/index.d.ts +24 -5
  92. package/dist/lib/secrets/index.js +70 -41
  93. package/dist/lib/session/active.js +5 -5
  94. package/dist/lib/session/db.js +4 -4
  95. package/dist/lib/session/discover.js +2 -2
  96. package/dist/lib/session/render.js +21 -7
  97. package/dist/lib/shims.d.ts +28 -4
  98. package/dist/lib/shims.js +72 -14
  99. package/dist/lib/state.d.ts +22 -28
  100. package/dist/lib/state.js +83 -78
  101. package/dist/lib/sync-manifest.d.ts +2 -2
  102. package/dist/lib/sync-manifest.js +5 -5
  103. package/dist/lib/teams/agents.d.ts +4 -2
  104. package/dist/lib/teams/agents.js +11 -4
  105. package/dist/lib/teams/api.d.ts +1 -1
  106. package/dist/lib/teams/api.js +2 -2
  107. package/dist/lib/teams/index.d.ts +1 -0
  108. package/dist/lib/teams/index.js +1 -0
  109. package/dist/lib/teams/persistence.js +3 -3
  110. package/dist/lib/teams/registry.d.ts +12 -1
  111. package/dist/lib/teams/registry.js +12 -2
  112. package/dist/lib/teams/worktree.d.ts +30 -0
  113. package/dist/lib/teams/worktree.js +96 -0
  114. package/dist/lib/types.d.ts +12 -6
  115. package/dist/lib/types.js +3 -3
  116. package/dist/lib/versions.d.ts +32 -3
  117. package/dist/lib/versions.js +147 -119
  118. package/package.json +3 -2
  119. package/scripts/postinstall.js +29 -0
  120. package/dist/commands/refresh-memory.d.ts +0 -15
  121. package/dist/lib/memory-compile.d.ts +0 -66
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Subagents resource handler.
3
+ *
4
+ * Subagents are YAML files stored in subagents/ directories across layers.
5
+ * Format is the same for all agents. Resolution order: project > user > system.
6
+ */
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+ import * as yaml from 'yaml';
10
+ import { getProjectAgentsDir, getUserSubagentsDir, getSystemSubagentsDir, getEnabledExtraRepos, } from '../state.js';
11
+ /** Get layer directories for subagent resolution. */
12
+ function getLayerDirs(cwd) {
13
+ const projectDir = getProjectAgentsDir(cwd);
14
+ const extraRepos = getEnabledExtraRepos();
15
+ return {
16
+ system: path.join(getSystemSubagentsDir()),
17
+ user: getUserSubagentsDir(),
18
+ project: projectDir ? path.join(projectDir, 'subagents') : null,
19
+ extra: extraRepos.map((e) => path.join(e.dir, 'subagents')),
20
+ };
21
+ }
22
+ /** Map source directory to layer name. */
23
+ function dirToLayer(dir, dirs) {
24
+ if (dirs.project && dir.startsWith(dirs.project))
25
+ return 'project';
26
+ if (dir.startsWith(dirs.user))
27
+ return 'user';
28
+ return 'system';
29
+ }
30
+ /** Parse a subagent YAML file and return parsed item. */
31
+ function parseSubagentYaml(filePath) {
32
+ if (!fs.existsSync(filePath)) {
33
+ return null;
34
+ }
35
+ try {
36
+ const content = fs.readFileSync(filePath, 'utf-8');
37
+ const parsed = yaml.parse(content);
38
+ if (!parsed || typeof parsed !== 'object') {
39
+ return null;
40
+ }
41
+ return {
42
+ name: parsed.name || '',
43
+ description: parsed.description || '',
44
+ model: parsed.model,
45
+ color: parsed.color,
46
+ config: parsed.config,
47
+ };
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ }
53
+ /** Extract name from filename (removes .yaml/.yml extension). */
54
+ function nameFromFile(filename) {
55
+ return filename.replace(/\.ya?ml$/, '');
56
+ }
57
+ export class SubagentsHandler {
58
+ kind = 'subagent';
59
+ /**
60
+ * List all subagents across layers, with higher layer winning on name conflict.
61
+ * Returns a union of all subagents, deduplicated by name.
62
+ */
63
+ listAll(_agent, cwd) {
64
+ const dirs = getLayerDirs(cwd);
65
+ const seen = new Set();
66
+ const results = [];
67
+ // Order: project > user > system > extra (extra comes last after system)
68
+ const layerDirs = [];
69
+ if (dirs.project && fs.existsSync(dirs.project)) {
70
+ layerDirs.push({ dir: dirs.project, layer: 'project' });
71
+ }
72
+ if (fs.existsSync(dirs.user)) {
73
+ layerDirs.push({ dir: dirs.user, layer: 'user' });
74
+ }
75
+ if (fs.existsSync(dirs.system)) {
76
+ layerDirs.push({ dir: dirs.system, layer: 'system' });
77
+ }
78
+ for (const extraDir of dirs.extra) {
79
+ if (fs.existsSync(extraDir)) {
80
+ layerDirs.push({ dir: extraDir, layer: 'system' });
81
+ }
82
+ }
83
+ for (const { dir, layer } of layerDirs) {
84
+ let entries;
85
+ try {
86
+ entries = fs.readdirSync(dir, { withFileTypes: true });
87
+ }
88
+ catch {
89
+ continue;
90
+ }
91
+ for (const entry of entries) {
92
+ if (!entry.isFile())
93
+ continue;
94
+ if (!entry.name.endsWith('.yaml') && !entry.name.endsWith('.yml'))
95
+ continue;
96
+ if (entry.name.startsWith('.'))
97
+ continue;
98
+ const name = nameFromFile(entry.name);
99
+ if (seen.has(name))
100
+ continue;
101
+ const filePath = path.join(dir, entry.name);
102
+ const item = parseSubagentYaml(filePath);
103
+ if (!item)
104
+ continue;
105
+ seen.add(name);
106
+ results.push({
107
+ name,
108
+ item,
109
+ layer,
110
+ path: filePath,
111
+ });
112
+ }
113
+ }
114
+ return results;
115
+ }
116
+ /**
117
+ * Resolve a single subagent by name.
118
+ * Returns the winning layer's version, or null if not found.
119
+ */
120
+ resolve(_agent, name, cwd) {
121
+ const dirs = getLayerDirs(cwd);
122
+ // Order: project > user > system > extra
123
+ const searchDirs = [];
124
+ if (dirs.project) {
125
+ searchDirs.push({ dir: dirs.project, layer: 'project' });
126
+ }
127
+ searchDirs.push({ dir: dirs.user, layer: 'user' });
128
+ searchDirs.push({ dir: dirs.system, layer: 'system' });
129
+ for (const extraDir of dirs.extra) {
130
+ searchDirs.push({ dir: extraDir, layer: 'system' });
131
+ }
132
+ for (const { dir, layer } of searchDirs) {
133
+ if (!fs.existsSync(dir))
134
+ continue;
135
+ // Try .yaml first, then .yml
136
+ for (const ext of ['.yaml', '.yml']) {
137
+ const filePath = path.join(dir, name + ext);
138
+ if (fs.existsSync(filePath)) {
139
+ const item = parseSubagentYaml(filePath);
140
+ if (item) {
141
+ return {
142
+ name,
143
+ item,
144
+ layer,
145
+ path: filePath,
146
+ };
147
+ }
148
+ }
149
+ }
150
+ }
151
+ return null;
152
+ }
153
+ /**
154
+ * Sync resolved subagents to the agent's version home directory.
155
+ * Copies YAML files to the target directory.
156
+ */
157
+ sync(agent, versionHome, cwd) {
158
+ const targetDir = path.join(versionHome, this.targetDir(agent));
159
+ // Ensure target directory exists
160
+ if (!fs.existsSync(targetDir)) {
161
+ fs.mkdirSync(targetDir, { recursive: true });
162
+ }
163
+ // Clear existing subagents in target
164
+ try {
165
+ const existing = fs.readdirSync(targetDir);
166
+ for (const file of existing) {
167
+ if (file.endsWith('.yaml') || file.endsWith('.yml')) {
168
+ fs.unlinkSync(path.join(targetDir, file));
169
+ }
170
+ }
171
+ }
172
+ catch {
173
+ // Ignore errors during cleanup
174
+ }
175
+ // Copy all resolved subagents
176
+ const resolved = this.listAll(agent, cwd);
177
+ for (const { name, path: sourcePath } of resolved) {
178
+ const ext = sourcePath.endsWith('.yml') ? '.yml' : '.yaml';
179
+ const targetPath = path.join(targetDir, name + ext);
180
+ fs.copyFileSync(sourcePath, targetPath);
181
+ }
182
+ }
183
+ /**
184
+ * Get the file format this resource uses for a given agent.
185
+ * Subagents always use YAML format.
186
+ */
187
+ format(_agent) {
188
+ return 'yaml';
189
+ }
190
+ /**
191
+ * Get the target directory name in the agent's version home.
192
+ */
193
+ targetDir(_agent) {
194
+ return 'subagents';
195
+ }
196
+ }
197
+ /** Singleton instance of the SubagentsHandler. */
198
+ export const subagentsHandler = new SubagentsHandler();
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Unified resource system types.
3
+ *
4
+ * Resources merge from three layers: system → user → project
5
+ * - Union: All resources from all layers are combined
6
+ * - Override on name conflict: Higher layer wins (project > user > system)
7
+ */
8
+ export type AgentId = 'claude' | 'codex' | 'gemini' | 'cursor' | 'opencode' | 'openclaw';
9
+ export type Layer = 'system' | 'user' | 'project';
10
+ export type ResourceKind = 'command' | 'hook' | 'skill' | 'rule' | 'mcp' | 'permission' | 'subagent';
11
+ /** A resolved resource with its origin layer. */
12
+ export interface ResolvedItem<T> {
13
+ name: string;
14
+ item: T;
15
+ layer: Layer;
16
+ path: string;
17
+ }
18
+ /**
19
+ * Resource handler interface.
20
+ *
21
+ * Each resource type (commands, hooks, skills, etc.) implements this interface
22
+ * to provide consistent list/resolve/sync behavior across all agent types.
23
+ */
24
+ export interface ResourceHandler<T> {
25
+ readonly kind: ResourceKind;
26
+ /**
27
+ * List all resources across layers, with higher layer winning on name conflict.
28
+ * Returns a union of all resources, deduplicated by name.
29
+ */
30
+ listAll(agent: AgentId, cwd?: string): ResolvedItem<T>[];
31
+ /**
32
+ * Resolve a single resource by name.
33
+ * Returns the winning layer's version, or null if not found.
34
+ */
35
+ resolve(agent: AgentId, name: string, cwd?: string): ResolvedItem<T> | null;
36
+ /**
37
+ * Sync resolved resources to the agent's version home directory.
38
+ * Copies/transforms resources as needed for the agent's expected format.
39
+ */
40
+ sync(agent: AgentId, versionHome: string, cwd?: string): void;
41
+ /**
42
+ * Get the file format this resource uses for a given agent.
43
+ */
44
+ format(agent: AgentId): 'md' | 'toml' | 'json' | 'yaml';
45
+ /**
46
+ * Get the target directory name in the agent's version home.
47
+ */
48
+ targetDir(agent: AgentId): string;
49
+ /**
50
+ * For resources that modify config files (MCP, permissions),
51
+ * return the config file path. Returns null if not applicable.
52
+ */
53
+ configPath?(agent: AgentId, versionHome: string): string | null;
54
+ /**
55
+ * Compute content hash for a resource item (for change detection).
56
+ * Used by diff() to detect modifications without full content comparison.
57
+ * Optional — handlers that don't implement this fall back to full sync.
58
+ */
59
+ hash?(item: T): string;
60
+ /**
61
+ * Compare source layers vs synced target to detect drift.
62
+ * Returns list of resources that differ (added, modified, removed).
63
+ * Enables incremental sync and "X resources out of sync" status.
64
+ * Optional — handlers that don't implement this always report "unknown".
65
+ */
66
+ diff?(agent: AgentId, versionHome: string, cwd?: string): ResourceDiff[];
67
+ }
68
+ /** Result of comparing source vs target for a single resource. */
69
+ export interface ResourceDiff {
70
+ name: string;
71
+ status: 'added' | 'modified' | 'removed';
72
+ sourceLayer: Layer | null;
73
+ sourceHash: string | null;
74
+ targetHash: string | null;
75
+ }
76
+ /** Helper to get layer directories for resource resolution. */
77
+ export interface LayerDirs {
78
+ system: string;
79
+ user: string;
80
+ project: string | null;
81
+ extra: string[];
82
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Unified resource system types.
3
+ *
4
+ * Resources merge from three layers: system → user → project
5
+ * - Union: All resources from all layers are combined
6
+ * - Override on name conflict: Higher layer wins (project > user > system)
7
+ */
8
+ export {};
@@ -8,7 +8,7 @@ import { AGENTS, listInstalledMcpsWithScope } from './agents.js';
8
8
  import { listInstalledCommandsWithScope } from './commands.js';
9
9
  import { listInstalledSkillsWithScope } from './skills.js';
10
10
  import { listInstalledHooksWithScope } from './hooks.js';
11
- import { listInstalledInstructionsWithScope } from './memory.js';
11
+ import { listInstalledInstructionsWithScope } from './rules/rules.js';
12
12
  import { getEffectiveHome } from './versions.js';
13
13
  import { listMcpServerConfigs } from './mcp.js';
14
14
  import { getProjectAgentsDir, getUserAgentsDir, getSystemAgentsDir, getEnabledExtraRepos, } from './state.js';
@@ -35,7 +35,14 @@ export declare const RUN_STRATEGIES: RunStrategy[];
35
35
  export declare function normalizeRunStrategy(value: unknown): RunStrategy | null;
36
36
  /** Read project-local run strategy from the nearest agents.yaml, if present. */
37
37
  export declare function getProjectRunStrategy(agent: AgentId, startPath: string): RunStrategy | null;
38
- /** Resolve the configured strategy: project agents.yaml, then ~/.agents-system/agents.yaml, then pinned. */
38
+ /**
39
+ * Resolve the configured strategy. Lookup order:
40
+ * 1. project-local agents.yaml (nearest to `startPath`)
41
+ * 2. ~/.agents-system/agents.yaml
42
+ * 3. default: `available` (use the pinned default version when healthy,
43
+ * otherwise fall through to a healthy account so a single rate-limited
44
+ * account doesn't block the run).
45
+ */
39
46
  export declare function getConfiguredRunStrategy(agent: AgentId, startPath?: string): RunStrategy;
40
47
  /** Persist the global run strategy used by bare `agents run <agent>`. */
41
48
  export declare function setGlobalRunStrategy(agent: AgentId, strategy: RunStrategy): void;
@@ -11,6 +11,12 @@ import { getAccountInfo } from './agents.js';
11
11
  import { readMeta, writeMeta, getAgentsDir } from './state.js';
12
12
  import { listInstalledVersions, getVersionHomePath, resolveVersion } from './versions.js';
13
13
  import { getUsageInfoByIdentity, getUsageLookupKey, isClaudeAuthValid, } from './usage.js';
14
+ const ROTATE_DIR = 'helpers/rotate';
15
+ function getRotateDir() {
16
+ const dir = path.join(getAgentsDir(), ROTATE_DIR);
17
+ fs.mkdirSync(dir, { recursive: true });
18
+ return dir;
19
+ }
14
20
  export const RUN_STRATEGIES = ['pinned', 'available', 'balanced'];
15
21
  /**
16
22
  * Return a run strategy when the input is valid, otherwise null.
@@ -47,11 +53,18 @@ export function getProjectRunStrategy(agent, startPath) {
47
53
  }
48
54
  return null;
49
55
  }
50
- /** Resolve the configured strategy: project agents.yaml, then ~/.agents-system/agents.yaml, then pinned. */
56
+ /**
57
+ * Resolve the configured strategy. Lookup order:
58
+ * 1. project-local agents.yaml (nearest to `startPath`)
59
+ * 2. ~/.agents-system/agents.yaml
60
+ * 3. default: `available` (use the pinned default version when healthy,
61
+ * otherwise fall through to a healthy account so a single rate-limited
62
+ * account doesn't block the run).
63
+ */
51
64
  export function getConfiguredRunStrategy(agent, startPath = process.cwd()) {
52
65
  return getProjectRunStrategy(agent, startPath)
53
66
  ?? normalizeRunStrategy(readMeta().run?.[agent]?.strategy)
54
- ?? 'pinned';
67
+ ?? 'available';
55
68
  }
56
69
  /** Persist the global run strategy used by bare `agents run <agent>`. */
57
70
  export function setGlobalRunStrategy(agent, strategy) {
@@ -279,7 +292,7 @@ export async function selectAvailableVersion(agent, preferredVersion) {
279
292
  * a torn write just means the next reader sees a stale timestamp (harmless).
280
293
  */
281
294
  function recordRotationPick(agent, version) {
282
- const stampPath = path.join(getAgentsDir(), `rotate-stamp-${agent}.json`);
295
+ const stampPath = path.join(getRotateDir(), `stamp-${agent}.json`);
283
296
  try {
284
297
  fs.writeFileSync(stampPath, JSON.stringify({ version, ts: Date.now() }), 'utf-8');
285
298
  }
@@ -290,7 +303,7 @@ function recordRotationPick(agent, version) {
290
303
  * or stamp is older than 60 seconds (stale).
291
304
  */
292
305
  function readRotationStamp(agent) {
293
- const stampPath = path.join(getAgentsDir(), `rotate-stamp-${agent}.json`);
306
+ const stampPath = path.join(getRotateDir(), `stamp-${agent}.json`);
294
307
  try {
295
308
  const raw = JSON.parse(fs.readFileSync(stampPath, 'utf-8'));
296
309
  if (Date.now() - raw.ts < 60_000)
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Rules file compilation -- resolving @-imports into a single flat file.
3
+ *
4
+ * Agents that do not natively resolve `@path/to/file` imports (Codex, Cursor)
5
+ * need a pre-compiled rules file with all imports inlined. This module
6
+ * handles that expansion for both user-scope (writes into version home) and
7
+ * project-scope (writes into the workspace).
8
+ */
9
+ import type { AgentId } from '../types.js';
10
+ import { type RulesLayer } from './compose.js';
11
+ /** Sidecar manifest recording source file hashes for staleness detection. */
12
+ export interface CompileManifest {
13
+ compiledAt: string;
14
+ sources: {
15
+ path: string;
16
+ sha256: string;
17
+ mtime?: number;
18
+ size?: number;
19
+ }[];
20
+ }
21
+ /** Result of resolving @-imports in a rules file. */
22
+ export interface ResolveResult {
23
+ /** Fully-inlined content. */
24
+ content: string;
25
+ /** Absolute paths of every file read during resolution (including the root). */
26
+ sources: string[];
27
+ }
28
+ /**
29
+ * Expand all `@path/to/file` imports in `content`, recursively up to
30
+ * MAX_DEPTH. Imports inside fenced code blocks and inline code spans are
31
+ * left alone, matching Claude Code's parser. Missing files are left as-is
32
+ * (silent skip), matching the documented behavior.
33
+ *
34
+ * Relative paths resolve against `baseDir`; absolute and tilde-prefixed
35
+ * paths resolve against the filesystem root / home directory.
36
+ */
37
+ export declare function resolveImports(content: string, baseDir: string): ResolveResult;
38
+ /** True if the agent's native runtime resolves `@path` imports in its rules file. */
39
+ export declare function supportsRulesImports(agentId: AgentId): boolean;
40
+ /**
41
+ * Fast staleness check. Returns true when:
42
+ * - the compiled file or its manifest is missing
43
+ * - any recorded source file is missing
44
+ * - any recorded source's sha256 no longer matches
45
+ *
46
+ * For agents that support @-imports natively, always returns false — there's
47
+ * nothing to compile.
48
+ */
49
+ export declare function isRulesStale(agentId: AgentId, version: string): boolean;
50
+ /**
51
+ * Resolve the source `rules/AGENTS.md` (with all @-imports expanded) and
52
+ * write the result into the version home, alongside a sidecar manifest that
53
+ * records source file hashes for staleness detection.
54
+ *
55
+ * Agents that natively resolve @-imports are skipped (no-op) — their sync
56
+ * uses the standard copyFileSync path in `syncResourcesToVersion`.
57
+ */
58
+ export declare function compileRulesForAgent(agentId: AgentId, version: string): {
59
+ compiled: boolean;
60
+ compiledPath: string;
61
+ sources: number;
62
+ };
63
+ /**
64
+ * Recompile rules if stale. Safe to call on every agent invocation — the
65
+ * staleness check is fast (sha256 of 8-10 small files, ~10-20ms). Returns
66
+ * true if a recompile happened, false otherwise.
67
+ */
68
+ export declare function ensureRulesFresh(agentId: AgentId, version: string): boolean;
69
+ export interface ProjectCompileResult {
70
+ /** True when cwd/AGENTS.md was newly written or rewritten. */
71
+ compiled: boolean;
72
+ /** Absolute path to cwd/AGENTS.md. Empty when no project rules dir was present. */
73
+ agentsPath: string;
74
+ /** Per-agent instruction filenames symlinked (or copied) to AGENTS.md. */
75
+ symlinks: string[];
76
+ /** Number of source files inlined (root + recursive @-imports). */
77
+ sources: number;
78
+ /** Per-agent files we left alone because the user wrote/owns them. */
79
+ skippedClobber: string[];
80
+ }
81
+ /**
82
+ * Compile project-scope rules into a workspace's root memory files so each
83
+ * agent's native loader picks them up.
84
+ *
85
+ * Composes rules from all available layers (project > user > extras > system)
86
+ * with project highest priority — so a project's `subrules/` and `rules.yaml`
87
+ * shadow user/system fragments and presets. Writes `cwd/AGENTS.md` with
88
+ * COMPILED_HEADER_PROJECT and creates symlinks (CLAUDE.md, GEMINI.md,
89
+ * .cursorrules, etc.) → AGENTS.md so every agent finds its expected file at
90
+ * cwd. The agent's own loader merges this project-level file with its
91
+ * user-level rules (in version home) at runtime.
92
+ *
93
+ * Don't-clobber guard: if `cwd/AGENTS.md` exists without our header, the user
94
+ * authored it — leave it alone and report via `skippedClobber`. Same for any
95
+ * pre-existing per-agent file or symlink that doesn't already point at
96
+ * AGENTS.md.
97
+ *
98
+ * No-op when `cwd/.agents/rules/` does not exist. Idempotent on repeated
99
+ * calls — content equality short-circuits the write.
100
+ */
101
+ export declare function compileRulesForProject(cwd: string, opts?: {
102
+ preset?: string;
103
+ layers?: RulesLayer[];
104
+ }): ProjectCompileResult;