byterover-cli 2.0.0 → 2.1.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.
- package/README.md +6 -81
- package/dist/agent/core/domain/llm/index.d.ts +1 -1
- package/dist/agent/core/domain/llm/index.js +1 -1
- package/dist/agent/core/domain/llm/registry.d.ts +8 -0
- package/dist/agent/core/domain/llm/registry.js +34 -0
- package/dist/agent/core/domain/sandbox/types.d.ts +2 -0
- package/dist/agent/core/domain/tools/constants.d.ts +3 -0
- package/dist/agent/core/domain/tools/constants.js +3 -0
- package/dist/agent/core/interfaces/cipher-services.d.ts +2 -4
- package/dist/agent/core/interfaces/i-cipher-agent.d.ts +9 -1
- package/dist/agent/core/interfaces/i-sandbox-service.d.ts +8 -0
- package/dist/agent/core/interfaces/i-tool-provider.d.ts +10 -0
- package/dist/agent/core/interfaces/i-tool-scheduler.d.ts +9 -0
- package/dist/agent/infra/agent/agent-schemas.d.ts +0 -9
- package/dist/agent/infra/agent/agent-schemas.js +0 -3
- package/dist/agent/infra/agent/cipher-agent.d.ts +25 -1
- package/dist/agent/infra/agent/cipher-agent.js +138 -11
- package/dist/agent/infra/agent/provider-update-config.d.ts +0 -2
- package/dist/agent/infra/agent/service-initializer.d.ts +2 -6
- package/dist/agent/infra/agent/service-initializer.js +45 -38
- package/dist/agent/infra/blob/blob-storage-factory.d.ts +2 -2
- package/dist/agent/infra/blob/blob-storage-factory.js +4 -4
- package/dist/agent/infra/blob/file-blob-storage.d.ts +96 -0
- package/dist/agent/infra/blob/file-blob-storage.js +454 -0
- package/dist/agent/infra/blob/index.d.ts +2 -3
- package/dist/agent/infra/blob/index.js +4 -6
- package/dist/agent/infra/llm/agent-llm-service.d.ts +3 -0
- package/dist/agent/infra/llm/agent-llm-service.js +34 -52
- package/dist/agent/infra/llm/context/compression/compression-helpers.d.ts +35 -0
- package/dist/agent/infra/llm/context/compression/compression-helpers.js +124 -0
- package/dist/agent/infra/llm/context/compression/escalated-compression.d.ts +62 -0
- package/dist/agent/infra/llm/context/compression/escalated-compression.js +144 -0
- package/dist/agent/infra/llm/context/compression/index.d.ts +3 -0
- package/dist/agent/infra/llm/context/compression/index.js +3 -0
- package/dist/agent/infra/llm/context/compression/reactive-overflow.d.ts +0 -27
- package/dist/agent/infra/llm/context/compression/reactive-overflow.js +5 -122
- package/dist/agent/infra/llm/context/context-manager.d.ts +20 -1
- package/dist/agent/infra/llm/context/context-manager.js +37 -7
- package/dist/agent/infra/llm/providers/index.js +0 -2
- package/dist/agent/infra/llm/providers/types.d.ts +1 -5
- package/dist/agent/infra/map/agentic-map-service.d.ts +97 -0
- package/dist/agent/infra/map/agentic-map-service.js +309 -0
- package/dist/agent/infra/map/context-tree-store.d.ts +94 -0
- package/dist/agent/infra/map/context-tree-store.js +278 -0
- package/dist/agent/infra/map/index.d.ts +4 -0
- package/dist/agent/infra/map/index.js +4 -0
- package/dist/agent/infra/map/llm-map-memory.d.ts +59 -0
- package/dist/agent/infra/map/llm-map-memory.js +187 -0
- package/dist/agent/infra/map/llm-map-service.d.ts +36 -0
- package/dist/agent/infra/map/llm-map-service.js +118 -0
- package/dist/agent/infra/map/map-shared.d.ts +140 -0
- package/dist/agent/infra/map/map-shared.js +325 -0
- package/dist/agent/infra/map/worker-pool.d.ts +45 -0
- package/dist/agent/infra/map/worker-pool.js +73 -0
- package/dist/agent/infra/sandbox/curation-helpers.d.ts +62 -0
- package/dist/agent/infra/sandbox/curation-helpers.js +219 -0
- package/dist/agent/infra/sandbox/sandbox-service.d.ts +12 -0
- package/dist/agent/infra/sandbox/sandbox-service.js +39 -7
- package/dist/agent/infra/sandbox/tools-sdk.d.ts +48 -1
- package/dist/agent/infra/sandbox/tools-sdk.js +52 -1
- package/dist/agent/infra/session/session-manager.d.ts +8 -1
- package/dist/agent/infra/session/session-manager.js +24 -4
- package/dist/agent/infra/storage/file-key-storage.d.ts +142 -0
- package/dist/agent/infra/storage/file-key-storage.js +572 -0
- package/dist/agent/infra/storage/granular-history-storage.d.ts +1 -1
- package/dist/agent/infra/storage/granular-history-storage.js +1 -1
- package/dist/agent/infra/system-prompt/contributors/context-tree-structure-contributor.d.ts +4 -0
- package/dist/agent/infra/system-prompt/contributors/context-tree-structure-contributor.js +42 -14
- package/dist/agent/infra/system-prompt/contributors/map-selection-contributor.d.ts +16 -0
- package/dist/agent/infra/system-prompt/contributors/map-selection-contributor.js +47 -0
- package/dist/agent/infra/tools/core-tool-scheduler.js +3 -1
- package/dist/agent/infra/tools/implementations/agentic-map-tool.d.ts +35 -0
- package/dist/agent/infra/tools/implementations/agentic-map-tool.js +156 -0
- package/dist/agent/infra/tools/implementations/code-exec-tool.js +1 -0
- package/dist/agent/infra/tools/implementations/curate-tool.d.ts +9 -9
- package/dist/agent/infra/tools/implementations/expand-knowledge-tool.d.ts +18 -0
- package/dist/agent/infra/tools/implementations/expand-knowledge-tool.js +43 -0
- package/dist/agent/infra/tools/implementations/llm-map-tool.d.ts +24 -0
- package/dist/agent/infra/tools/implementations/llm-map-tool.js +87 -0
- package/dist/agent/infra/tools/implementations/memory-symbol-tree.d.ts +28 -1
- package/dist/agent/infra/tools/implementations/memory-symbol-tree.js +27 -3
- package/dist/agent/infra/tools/implementations/search-knowledge-service.d.ts +1 -0
- package/dist/agent/infra/tools/implementations/search-knowledge-service.js +83 -12
- package/dist/agent/infra/tools/implementations/search-knowledge-tool.js +2 -2
- package/dist/agent/infra/tools/tool-manager.js +6 -0
- package/dist/agent/infra/tools/tool-provider.d.ts +12 -0
- package/dist/agent/infra/tools/tool-provider.js +78 -0
- package/dist/agent/infra/tools/tool-registry.d.ts +14 -0
- package/dist/agent/infra/tools/tool-registry.js +32 -0
- package/dist/agent/resources/prompts/system-prompt.yml +48 -74
- package/dist/agent/resources/tools/expand_knowledge.txt +20 -0
- package/dist/oclif/commands/curate/index.js +1 -2
- package/dist/oclif/commands/main.js +1 -0
- package/dist/oclif/commands/providers/connect.d.ts +1 -3
- package/dist/oclif/commands/providers/connect.js +7 -29
- package/dist/oclif/commands/query.js +1 -2
- package/dist/server/constants.d.ts +7 -0
- package/dist/server/constants.js +8 -0
- package/dist/server/core/domain/entities/provider-registry.js +1 -15
- package/dist/server/core/domain/knowledge/memory-scoring.js +1 -1
- package/dist/server/core/domain/knowledge/summary-types.d.ts +126 -0
- package/dist/server/core/domain/knowledge/summary-types.js +7 -0
- package/dist/server/core/domain/transport/schemas.d.ts +0 -4
- package/dist/server/core/interfaces/context-tree/i-context-tree-archive-service.d.ts +30 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-archive-service.js +1 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-manifest-service.d.ts +30 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-manifest-service.js +1 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-summary-service.d.ts +29 -0
- package/dist/server/core/interfaces/context-tree/i-context-tree-summary-service.js +1 -0
- package/dist/server/infra/cogit/context-tree-to-push-context-mapper.js +10 -3
- package/dist/server/infra/connectors/skill/skill-connector.d.ts +4 -0
- package/dist/server/infra/connectors/skill/skill-connector.js +4 -0
- package/dist/server/infra/context-tree/children-hash.d.ts +20 -0
- package/dist/server/infra/context-tree/children-hash.js +22 -0
- package/dist/server/infra/context-tree/derived-artifact.d.ts +28 -0
- package/dist/server/infra/context-tree/derived-artifact.js +48 -0
- package/dist/server/infra/context-tree/file-context-tree-archive-service.d.ts +37 -0
- package/dist/server/infra/context-tree/file-context-tree-archive-service.js +219 -0
- package/dist/server/infra/context-tree/file-context-tree-manifest-service.d.ts +50 -0
- package/dist/server/infra/context-tree/file-context-tree-manifest-service.js +278 -0
- package/dist/server/infra/context-tree/file-context-tree-merger.js +4 -0
- package/dist/server/infra/context-tree/file-context-tree-snapshot-service.js +12 -4
- package/dist/server/infra/context-tree/file-context-tree-summary-service.d.ts +44 -0
- package/dist/server/infra/context-tree/file-context-tree-summary-service.js +313 -0
- package/dist/server/infra/context-tree/file-context-tree-writer-service.js +5 -0
- package/dist/server/infra/context-tree/prompts/summary-generation.d.ts +22 -0
- package/dist/server/infra/context-tree/prompts/summary-generation.js +45 -0
- package/dist/server/infra/context-tree/snapshot-diff.d.ts +19 -0
- package/dist/server/infra/context-tree/snapshot-diff.js +39 -0
- package/dist/server/infra/context-tree/summary-frontmatter.d.ts +24 -0
- package/dist/server/infra/context-tree/summary-frontmatter.js +111 -0
- package/dist/server/infra/daemon/agent-process.js +2 -14
- package/dist/server/infra/executor/curate-executor.d.ts +1 -0
- package/dist/server/infra/executor/curate-executor.js +82 -34
- package/dist/server/infra/executor/folder-pack-executor.js +1 -1
- package/dist/server/infra/executor/pre-compaction/compaction-escalation.d.ts +6 -0
- package/dist/server/infra/executor/pre-compaction/compaction-escalation.js +6 -0
- package/dist/server/infra/executor/pre-compaction/index.d.ts +3 -0
- package/dist/server/infra/executor/pre-compaction/index.js +1 -0
- package/dist/server/infra/executor/pre-compaction/pre-compaction-service.d.ts +59 -0
- package/dist/server/infra/executor/pre-compaction/pre-compaction-service.js +124 -0
- package/dist/server/infra/executor/pre-compaction/prompts.d.ts +24 -0
- package/dist/server/infra/executor/pre-compaction/prompts.js +47 -0
- package/dist/server/infra/executor/query-executor.d.ts +3 -0
- package/dist/server/infra/executor/query-executor.js +39 -4
- package/dist/server/infra/http/authenticated-http-client.js +4 -0
- package/dist/server/infra/http/provider-model-fetcher-registry.js +1 -5
- package/dist/server/infra/http/provider-model-fetchers.d.ts +0 -14
- package/dist/server/infra/http/provider-model-fetchers.js +0 -132
- package/dist/server/infra/provider/provider-config-resolver.js +0 -55
- package/dist/server/utils/curate-result-parser.d.ts +4 -4
- package/dist/shared/constants/curation.d.ts +6 -0
- package/dist/shared/constants/curation.js +6 -0
- package/dist/shared/utils/escalation-utils.d.ts +59 -0
- package/dist/shared/utils/escalation-utils.js +141 -0
- package/dist/tui/components/command-input.js +1 -1
- package/dist/tui/components/inline-prompts/inline-confirm.js +6 -1
- package/dist/tui/features/commands/definitions/exit.d.ts +2 -0
- package/dist/tui/features/commands/definitions/exit.js +9 -0
- package/dist/tui/features/commands/definitions/index.js +3 -0
- package/dist/tui/features/exit/components/exit-flow.d.ts +10 -0
- package/dist/tui/features/exit/components/exit-flow.js +19 -0
- package/dist/tui/features/provider/components/provider-flow.js +1 -21
- package/oclif.manifest.json +100 -109
- package/package.json +11 -4
- package/dist/agent/infra/blob/migrations.d.ts +0 -63
- package/dist/agent/infra/blob/migrations.js +0 -148
- package/dist/agent/infra/blob/sqlite-blob-storage.d.ts +0 -82
- package/dist/agent/infra/blob/sqlite-blob-storage.js +0 -307
- package/dist/agent/infra/llm/providers/google-vertex.d.ts +0 -15
- package/dist/agent/infra/llm/providers/google-vertex.js +0 -36
- package/dist/agent/infra/storage/blob-history-storage.d.ts +0 -81
- package/dist/agent/infra/storage/blob-history-storage.js +0 -193
- package/dist/agent/infra/storage/dual-format-history-storage.d.ts +0 -83
- package/dist/agent/infra/storage/dual-format-history-storage.js +0 -165
- package/dist/agent/infra/storage/sqlite-key-storage.d.ts +0 -113
- package/dist/agent/infra/storage/sqlite-key-storage.js +0 -438
- package/dist/server/infra/provider/vertex-ai-utils.d.ts +0 -10
- package/dist/server/infra/provider/vertex-ai-utils.js +0 -28
- package/dist/tui/features/provider/components/credential-path-dialog.d.ts +0 -30
- package/dist/tui/features/provider/components/credential-path-dialog.js +0 -85
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CogitPushContext } from '../../core/domain/entities/cogit-push-context.js';
|
|
2
|
+
import { isExcludedFromSync } from '../context-tree/derived-artifact.js';
|
|
2
3
|
/**
|
|
3
4
|
* Maps context file contents to CogitPushContext instances for the CoGit API.
|
|
4
5
|
* Converts file reader output to the format expected by the push service.
|
|
@@ -7,21 +8,27 @@ import { CogitPushContext } from '../../core/domain/entities/cogit-push-context.
|
|
|
7
8
|
* @returns Array of CogitPushContext instances ready for the push API
|
|
8
9
|
*/
|
|
9
10
|
export const mapToPushContexts = (params) => {
|
|
10
|
-
const addedContextFiles = params.addedFiles
|
|
11
|
+
const addedContextFiles = params.addedFiles
|
|
12
|
+
.filter((file) => !isExcludedFromSync(file.path))
|
|
13
|
+
.map((file) => new CogitPushContext({
|
|
11
14
|
content: file.content,
|
|
12
15
|
operation: 'add',
|
|
13
16
|
path: file.path,
|
|
14
17
|
tags: file.tags,
|
|
15
18
|
title: file.title,
|
|
16
19
|
}));
|
|
17
|
-
const editedContextFiles = params.modifiedFiles
|
|
20
|
+
const editedContextFiles = params.modifiedFiles
|
|
21
|
+
.filter((file) => !isExcludedFromSync(file.path))
|
|
22
|
+
.map((file) => new CogitPushContext({
|
|
18
23
|
content: file.content,
|
|
19
24
|
operation: 'edit',
|
|
20
25
|
path: file.path,
|
|
21
26
|
tags: file.tags,
|
|
22
27
|
title: file.title,
|
|
23
28
|
}));
|
|
24
|
-
const deletedContextFiles = params.deletedPaths
|
|
29
|
+
const deletedContextFiles = params.deletedPaths
|
|
30
|
+
.filter((deletedPath) => !isExcludedFromSync(deletedPath))
|
|
31
|
+
.map((deletedPath) => new CogitPushContext({
|
|
25
32
|
content: '',
|
|
26
33
|
operation: 'delete',
|
|
27
34
|
path: deletedPath,
|
|
@@ -39,6 +39,10 @@ export declare class SkillConnector implements IConnector {
|
|
|
39
39
|
* Write files to a named skill subdirectory for the given agent.
|
|
40
40
|
* Used by hub install to write downloaded skill files to e.g. `.claude/skills/{skillName}/`.
|
|
41
41
|
*
|
|
42
|
+
* @param agent - Agent connector target
|
|
43
|
+
* @param skillName - Skill folder name to create under the connector path
|
|
44
|
+
* @param files - Skill files to write
|
|
45
|
+
* @param options - Optional install scope
|
|
42
46
|
* @param options.scope - 'global' writes to home dir, 'project' (default) writes to project root
|
|
43
47
|
*/
|
|
44
48
|
writeSkillFiles(agent: Agent, skillName: string, files: Array<{
|
|
@@ -216,6 +216,10 @@ export class SkillConnector {
|
|
|
216
216
|
* Write files to a named skill subdirectory for the given agent.
|
|
217
217
|
* Used by hub install to write downloaded skill files to e.g. `.claude/skills/{skillName}/`.
|
|
218
218
|
*
|
|
219
|
+
* @param agent - Agent connector target
|
|
220
|
+
* @param skillName - Skill folder name to create under the connector path
|
|
221
|
+
* @param files - Skill files to write
|
|
222
|
+
* @param options - Optional install scope
|
|
219
223
|
* @param options.scope - 'global' writes to home dir, 'project' (default) writes to project root
|
|
220
224
|
*/
|
|
221
225
|
async writeSkillFiles(agent, skillName, files, options) {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Children hash utility for summary staleness detection.
|
|
3
|
+
*
|
|
4
|
+
* Computes a deterministic hash from child paths and their content hashes.
|
|
5
|
+
* Including paths (not just content hashes) ensures that renames and moves
|
|
6
|
+
* are detected as structural changes.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Compute a deterministic hash of children for staleness detection.
|
|
10
|
+
*
|
|
11
|
+
* The hash includes both the relative path and content hash of each child,
|
|
12
|
+
* sorted by path for determinism. This detects:
|
|
13
|
+
* - Content changes (different contentHash)
|
|
14
|
+
* - Renames/moves (different path, same contentHash)
|
|
15
|
+
* - Additions/deletions (different set of paths)
|
|
16
|
+
*/
|
|
17
|
+
export declare function computeChildrenHash(children: Array<{
|
|
18
|
+
contentHash: string;
|
|
19
|
+
path: string;
|
|
20
|
+
}>): string;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Children hash utility for summary staleness detection.
|
|
3
|
+
*
|
|
4
|
+
* Computes a deterministic hash from child paths and their content hashes.
|
|
5
|
+
* Including paths (not just content hashes) ensures that renames and moves
|
|
6
|
+
* are detected as structural changes.
|
|
7
|
+
*/
|
|
8
|
+
import { computeContentHash } from './hash-utils.js';
|
|
9
|
+
/**
|
|
10
|
+
* Compute a deterministic hash of children for staleness detection.
|
|
11
|
+
*
|
|
12
|
+
* The hash includes both the relative path and content hash of each child,
|
|
13
|
+
* sorted by path for determinism. This detects:
|
|
14
|
+
* - Content changes (different contentHash)
|
|
15
|
+
* - Renames/moves (different path, same contentHash)
|
|
16
|
+
* - Additions/deletions (different set of paths)
|
|
17
|
+
*/
|
|
18
|
+
export function computeChildrenHash(children) {
|
|
19
|
+
const sorted = [...children].sort((a, b) => a.path.localeCompare(b.path));
|
|
20
|
+
const input = sorted.map((c) => `${c.path}:${c.contentHash}`).join('\n');
|
|
21
|
+
return computeContentHash(input);
|
|
22
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derived-artifact predicates for the Hierarchical DAG architecture.
|
|
3
|
+
*
|
|
4
|
+
* Three predicates with clear separation of concerns:
|
|
5
|
+
* - isDerivedArtifact() — non-searchable derived content (excluded from query fingerprint)
|
|
6
|
+
* - isArchiveStub() — searchable stubs (included in BM25 index and fingerprint)
|
|
7
|
+
* - isExcludedFromSync() — union of above (excluded from snapshot/sync/merge/push)
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Returns true if the given relative path is a derived artifact
|
|
11
|
+
* that should be excluded from snapshot tracking, CoGit sync,
|
|
12
|
+
* and query cache fingerprinting.
|
|
13
|
+
*
|
|
14
|
+
* Derived artifacts: _index.md, _manifest.json, _archived/*.full.md
|
|
15
|
+
* NOTE: _archived/*.stub.md are NOT derived — they are searchable.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isDerivedArtifact(relativePath: string): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Returns true if the path is an archive stub (.stub.md inside _archived/).
|
|
20
|
+
* Stubs are searchable but excluded from snapshot/sync.
|
|
21
|
+
*/
|
|
22
|
+
export declare function isArchiveStub(relativePath: string): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Returns true if the path should be excluded from snapshot tracking,
|
|
25
|
+
* CoGit sync (push/pull/merge), and writer operations.
|
|
26
|
+
* This includes ALL derived artifacts plus searchable stubs.
|
|
27
|
+
*/
|
|
28
|
+
export declare function isExcludedFromSync(relativePath: string): boolean;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derived-artifact predicates for the Hierarchical DAG architecture.
|
|
3
|
+
*
|
|
4
|
+
* Three predicates with clear separation of concerns:
|
|
5
|
+
* - isDerivedArtifact() — non-searchable derived content (excluded from query fingerprint)
|
|
6
|
+
* - isArchiveStub() — searchable stubs (included in BM25 index and fingerprint)
|
|
7
|
+
* - isExcludedFromSync() — union of above (excluded from snapshot/sync/merge/push)
|
|
8
|
+
*/
|
|
9
|
+
import { ARCHIVE_DIR, FULL_ARCHIVE_EXTENSION, MANIFEST_FILE, STUB_EXTENSION, SUMMARY_INDEX_FILE } from '../../constants.js';
|
|
10
|
+
import { toUnixPath } from './path-utils.js';
|
|
11
|
+
/**
|
|
12
|
+
* Returns true if the given relative path is a derived artifact
|
|
13
|
+
* that should be excluded from snapshot tracking, CoGit sync,
|
|
14
|
+
* and query cache fingerprinting.
|
|
15
|
+
*
|
|
16
|
+
* Derived artifacts: _index.md, _manifest.json, _archived/*.full.md
|
|
17
|
+
* NOTE: _archived/*.stub.md are NOT derived — they are searchable.
|
|
18
|
+
*/
|
|
19
|
+
export function isDerivedArtifact(relativePath) {
|
|
20
|
+
const normalized = toUnixPath(relativePath);
|
|
21
|
+
const segments = normalized.split('/');
|
|
22
|
+
const fileName = segments.at(-1) ?? '';
|
|
23
|
+
if (fileName === SUMMARY_INDEX_FILE)
|
|
24
|
+
return true;
|
|
25
|
+
if (fileName === MANIFEST_FILE)
|
|
26
|
+
return true;
|
|
27
|
+
if (segments.includes(ARCHIVE_DIR) && fileName.endsWith(FULL_ARCHIVE_EXTENSION))
|
|
28
|
+
return true;
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Returns true if the path is an archive stub (.stub.md inside _archived/).
|
|
33
|
+
* Stubs are searchable but excluded from snapshot/sync.
|
|
34
|
+
*/
|
|
35
|
+
export function isArchiveStub(relativePath) {
|
|
36
|
+
const normalized = toUnixPath(relativePath);
|
|
37
|
+
const segments = normalized.split('/');
|
|
38
|
+
const fileName = segments.at(-1) ?? '';
|
|
39
|
+
return segments.includes(ARCHIVE_DIR) && fileName.endsWith(STUB_EXTENSION);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Returns true if the path should be excluded from snapshot tracking,
|
|
43
|
+
* CoGit sync (push/pull/merge), and writer operations.
|
|
44
|
+
* This includes ALL derived artifacts plus searchable stubs.
|
|
45
|
+
*/
|
|
46
|
+
export function isExcludedFromSync(relativePath) {
|
|
47
|
+
return isDerivedArtifact(relativePath) || isArchiveStub(relativePath);
|
|
48
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-based implementation of IContextTreeArchiveService.
|
|
3
|
+
*
|
|
4
|
+
* Archives low-importance context entries into _archived/ with:
|
|
5
|
+
* - .full.md: lossless preserved original content
|
|
6
|
+
* - .stub.md: searchable ghost cue (~220 tokens) with lineage pointers
|
|
7
|
+
*
|
|
8
|
+
* Archive naming preserves relative paths to avoid collisions:
|
|
9
|
+
* auth/jwt-tokens/refresh-flow.md → _archived/auth/jwt-tokens/refresh-flow.stub.md
|
|
10
|
+
*
|
|
11
|
+
* Fail-open: any error during ghost cue generation falls back to deterministic truncation.
|
|
12
|
+
*/
|
|
13
|
+
import type { ICipherAgent } from '../../../agent/core/interfaces/i-cipher-agent.js';
|
|
14
|
+
import type { ArchiveResult, DrillDownResult } from '../../core/domain/knowledge/summary-types.js';
|
|
15
|
+
import type { IContextTreeArchiveService } from '../../core/interfaces/context-tree/i-context-tree-archive-service.js';
|
|
16
|
+
export declare class FileContextTreeArchiveService implements IContextTreeArchiveService {
|
|
17
|
+
archiveEntry(relativePath: string, agent: ICipherAgent, directory?: string): Promise<ArchiveResult>;
|
|
18
|
+
drillDown(stubPath: string, directory?: string): Promise<DrillDownResult>;
|
|
19
|
+
findArchiveCandidates(directory?: string): Promise<string[]>;
|
|
20
|
+
restoreEntry(stubPath: string, directory?: string): Promise<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Extract importance score from frontmatter. Returns 50 if not found.
|
|
23
|
+
*/
|
|
24
|
+
private extractImportance;
|
|
25
|
+
/**
|
|
26
|
+
* Generate a ghost cue using LLM with deterministic fallback.
|
|
27
|
+
*/
|
|
28
|
+
private generateGhostCue;
|
|
29
|
+
/**
|
|
30
|
+
* Parse FrontmatterScoring fields from content frontmatter.
|
|
31
|
+
*/
|
|
32
|
+
private parseScoring;
|
|
33
|
+
/**
|
|
34
|
+
* Recursively scan context tree for archive candidates.
|
|
35
|
+
*/
|
|
36
|
+
private scanForCandidates;
|
|
37
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/* eslint-disable camelcase */
|
|
2
|
+
/**
|
|
3
|
+
* File-based implementation of IContextTreeArchiveService.
|
|
4
|
+
*
|
|
5
|
+
* Archives low-importance context entries into _archived/ with:
|
|
6
|
+
* - .full.md: lossless preserved original content
|
|
7
|
+
* - .stub.md: searchable ghost cue (~220 tokens) with lineage pointers
|
|
8
|
+
*
|
|
9
|
+
* Archive naming preserves relative paths to avoid collisions:
|
|
10
|
+
* auth/jwt-tokens/refresh-flow.md → _archived/auth/jwt-tokens/refresh-flow.stub.md
|
|
11
|
+
*
|
|
12
|
+
* Fail-open: any error during ghost cue generation falls back to deterministic truncation.
|
|
13
|
+
*/
|
|
14
|
+
import { mkdir, readFile, unlink, writeFile } from 'node:fs/promises';
|
|
15
|
+
import { dirname, extname, join } from 'node:path';
|
|
16
|
+
import { ARCHIVE_DIR, ARCHIVE_IMPORTANCE_THRESHOLD, BRV_DIR, CONTEXT_FILE_EXTENSION, CONTEXT_TREE_DIR, DEFAULT_GHOST_CUE_MAX_TOKENS, FULL_ARCHIVE_EXTENSION, STUB_EXTENSION, } from '../../constants.js';
|
|
17
|
+
import { applyDecay } from '../../core/domain/knowledge/memory-scoring.js';
|
|
18
|
+
import { estimateTokens } from '../executor/pre-compaction/compaction-escalation.js';
|
|
19
|
+
import { isArchiveStub, isDerivedArtifact } from './derived-artifact.js';
|
|
20
|
+
import { toUnixPath } from './path-utils.js';
|
|
21
|
+
import { generateArchiveStubContent, parseArchiveStubFrontmatter } from './summary-frontmatter.js';
|
|
22
|
+
export class FileContextTreeArchiveService {
|
|
23
|
+
async archiveEntry(relativePath, agent, directory) {
|
|
24
|
+
const baseDir = directory ?? process.cwd();
|
|
25
|
+
const contextTreeDir = join(baseDir, BRV_DIR, CONTEXT_TREE_DIR);
|
|
26
|
+
const originalFullPath = join(contextTreeDir, relativePath);
|
|
27
|
+
// Read original content
|
|
28
|
+
const content = await readFile(originalFullPath, 'utf8');
|
|
29
|
+
const originalTokenCount = estimateTokens(content);
|
|
30
|
+
// Compute archive paths: replace extension with .stub.md / .full.md
|
|
31
|
+
const pathWithoutExt = relativePath.slice(0, -extname(relativePath).length);
|
|
32
|
+
const stubRelPath = join(ARCHIVE_DIR, `${pathWithoutExt}${STUB_EXTENSION}`);
|
|
33
|
+
const fullRelPath = join(ARCHIVE_DIR, `${pathWithoutExt}${FULL_ARCHIVE_EXTENSION}`);
|
|
34
|
+
const stubFullPath = join(contextTreeDir, stubRelPath);
|
|
35
|
+
const fullFullPath = join(contextTreeDir, fullRelPath);
|
|
36
|
+
// Create parent directories under _archived/
|
|
37
|
+
await mkdir(dirname(stubFullPath), { recursive: true });
|
|
38
|
+
// Write .full.md — verbatim original content (lossless)
|
|
39
|
+
await writeFile(fullFullPath, content, 'utf8');
|
|
40
|
+
// Generate ghost cue via LLM (fail-open to deterministic truncation)
|
|
41
|
+
const ghostCue = await this.generateGhostCue(agent, content);
|
|
42
|
+
const ghostCueTokenCount = estimateTokens(ghostCue);
|
|
43
|
+
// Parse frontmatter to get importance for eviction metadata
|
|
44
|
+
const importance = this.extractImportance(content);
|
|
45
|
+
// Write .stub.md with archive stub frontmatter
|
|
46
|
+
const stubContent = generateArchiveStubContent({
|
|
47
|
+
evicted_at: new Date().toISOString(),
|
|
48
|
+
evicted_importance: importance,
|
|
49
|
+
original_path: relativePath,
|
|
50
|
+
original_token_count: originalTokenCount,
|
|
51
|
+
points_to: toUnixPath(fullRelPath),
|
|
52
|
+
type: 'archive_stub',
|
|
53
|
+
}, ghostCue);
|
|
54
|
+
await writeFile(stubFullPath, stubContent, 'utf8');
|
|
55
|
+
// Delete original file
|
|
56
|
+
await unlink(originalFullPath);
|
|
57
|
+
return {
|
|
58
|
+
fullPath: toUnixPath(fullRelPath),
|
|
59
|
+
ghostCueTokenCount,
|
|
60
|
+
originalPath: relativePath,
|
|
61
|
+
stubPath: toUnixPath(stubRelPath),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
async drillDown(stubPath, directory) {
|
|
65
|
+
const baseDir = directory ?? process.cwd();
|
|
66
|
+
const contextTreeDir = join(baseDir, BRV_DIR, CONTEXT_TREE_DIR);
|
|
67
|
+
const stubFullPath = join(contextTreeDir, stubPath);
|
|
68
|
+
// Parse stub to get points_to
|
|
69
|
+
const stubContent = await readFile(stubFullPath, 'utf8');
|
|
70
|
+
const fm = parseArchiveStubFrontmatter(stubContent);
|
|
71
|
+
if (!fm) {
|
|
72
|
+
throw new Error(`Invalid archive stub: ${stubPath}`);
|
|
73
|
+
}
|
|
74
|
+
// Read full content
|
|
75
|
+
const fullPath = join(contextTreeDir, fm.points_to);
|
|
76
|
+
const fullContent = await readFile(fullPath, 'utf8');
|
|
77
|
+
return {
|
|
78
|
+
fullContent,
|
|
79
|
+
originalPath: fm.original_path,
|
|
80
|
+
tokenCount: estimateTokens(fullContent),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
async findArchiveCandidates(directory) {
|
|
84
|
+
const baseDir = directory ?? process.cwd();
|
|
85
|
+
const contextTreeDir = join(baseDir, BRV_DIR, CONTEXT_TREE_DIR);
|
|
86
|
+
const candidates = [];
|
|
87
|
+
await this.scanForCandidates(contextTreeDir, contextTreeDir, candidates);
|
|
88
|
+
return candidates;
|
|
89
|
+
}
|
|
90
|
+
async restoreEntry(stubPath, directory) {
|
|
91
|
+
const baseDir = directory ?? process.cwd();
|
|
92
|
+
const contextTreeDir = join(baseDir, BRV_DIR, CONTEXT_TREE_DIR);
|
|
93
|
+
const stubFullPath = join(contextTreeDir, stubPath);
|
|
94
|
+
// Parse stub to get original_path and points_to
|
|
95
|
+
const stubContent = await readFile(stubFullPath, 'utf8');
|
|
96
|
+
const fm = parseArchiveStubFrontmatter(stubContent);
|
|
97
|
+
if (!fm) {
|
|
98
|
+
throw new Error(`Invalid archive stub: ${stubPath}`);
|
|
99
|
+
}
|
|
100
|
+
// Read full content
|
|
101
|
+
const fullPath = join(contextTreeDir, fm.points_to);
|
|
102
|
+
const fullContent = await readFile(fullPath, 'utf8');
|
|
103
|
+
// Write to original path (restore)
|
|
104
|
+
const restoredPath = join(contextTreeDir, fm.original_path);
|
|
105
|
+
await mkdir(dirname(restoredPath), { recursive: true });
|
|
106
|
+
await writeFile(restoredPath, fullContent, 'utf8');
|
|
107
|
+
// Delete stub and full archive files
|
|
108
|
+
await unlink(stubFullPath);
|
|
109
|
+
await unlink(fullPath);
|
|
110
|
+
return fm.original_path;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Extract importance score from frontmatter. Returns 50 if not found.
|
|
114
|
+
*/
|
|
115
|
+
extractImportance(content) {
|
|
116
|
+
const match = /^importance:\s*(\d+(?:\.\d+)?)/m.exec(content);
|
|
117
|
+
return match ? Number.parseFloat(match[1]) : 50;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Generate a ghost cue using LLM with deterministic fallback.
|
|
121
|
+
*/
|
|
122
|
+
async generateGhostCue(agent, content) {
|
|
123
|
+
try {
|
|
124
|
+
const taskId = `ghost_cue_${Date.now()}`;
|
|
125
|
+
const sessionId = await agent.createTaskSession(taskId, 'query');
|
|
126
|
+
try {
|
|
127
|
+
const prompt = `Summarize the following knowledge entry in ~${DEFAULT_GHOST_CUE_MAX_TOKENS} tokens or less. Output ONLY the summary. Preserve key entity names and relationships.
|
|
128
|
+
|
|
129
|
+
<content>
|
|
130
|
+
${content.slice(0, 8000)}
|
|
131
|
+
</content>`;
|
|
132
|
+
const response = await agent.executeOnSession(sessionId, prompt, {
|
|
133
|
+
executionContext: {
|
|
134
|
+
clearHistory: true,
|
|
135
|
+
commandType: 'query',
|
|
136
|
+
maxIterations: 1,
|
|
137
|
+
maxTokens: DEFAULT_GHOST_CUE_MAX_TOKENS * 4, // chars ≈ tokens * 4
|
|
138
|
+
temperature: 0.3,
|
|
139
|
+
},
|
|
140
|
+
taskId,
|
|
141
|
+
});
|
|
142
|
+
if (response && response.trim().length > 20) {
|
|
143
|
+
return response.trim();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
await agent.deleteTaskSession(sessionId);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// Fall through to deterministic fallback
|
|
152
|
+
}
|
|
153
|
+
// Deterministic fallback: truncate content
|
|
154
|
+
return `${content.replaceAll(/\s+/g, ' ').trim().slice(0, 320)}...`;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Parse FrontmatterScoring fields from content frontmatter.
|
|
158
|
+
*/
|
|
159
|
+
parseScoring(content) {
|
|
160
|
+
const scoring = {};
|
|
161
|
+
const importanceMatch = /^importance:\s*(\d+(?:\.\d+)?)/m.exec(content);
|
|
162
|
+
if (importanceMatch)
|
|
163
|
+
scoring.importance = Number.parseFloat(importanceMatch[1]);
|
|
164
|
+
const maturityMatch = /^maturity:\s*['"]?(core|draft|validated)['"]?/m.exec(content);
|
|
165
|
+
if (maturityMatch)
|
|
166
|
+
scoring.maturity = maturityMatch[1];
|
|
167
|
+
const updatedMatch = /^updatedAt:\s*['"]?(.+?)['"]?\s*$/m.exec(content);
|
|
168
|
+
if (updatedMatch)
|
|
169
|
+
scoring.updatedAt = updatedMatch[1];
|
|
170
|
+
return scoring;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Recursively scan context tree for archive candidates.
|
|
174
|
+
*/
|
|
175
|
+
async scanForCandidates(currentDir, contextTreeDir, candidates) {
|
|
176
|
+
const { readdir: readdirFs } = await import('node:fs/promises');
|
|
177
|
+
let entries;
|
|
178
|
+
try {
|
|
179
|
+
entries = await readdirFs(currentDir, { withFileTypes: true });
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const now = Date.now();
|
|
185
|
+
/* eslint-disable no-await-in-loop */
|
|
186
|
+
for (const entry of entries) {
|
|
187
|
+
const entryName = entry.name;
|
|
188
|
+
const fullPath = join(currentDir, entryName);
|
|
189
|
+
if (entry.isDirectory()) {
|
|
190
|
+
if (entryName === ARCHIVE_DIR)
|
|
191
|
+
continue;
|
|
192
|
+
await this.scanForCandidates(fullPath, contextTreeDir, candidates);
|
|
193
|
+
}
|
|
194
|
+
else if (entry.isFile() && entryName.endsWith(CONTEXT_FILE_EXTENSION)) {
|
|
195
|
+
const relativePath = toUnixPath(fullPath.slice(contextTreeDir.length + 1));
|
|
196
|
+
if (isDerivedArtifact(relativePath) || isArchiveStub(relativePath))
|
|
197
|
+
continue;
|
|
198
|
+
try {
|
|
199
|
+
const content = await readFile(fullPath, 'utf8');
|
|
200
|
+
const scoring = this.parseScoring(content);
|
|
201
|
+
// Only archive draft entries below importance threshold
|
|
202
|
+
if (scoring.maturity !== 'draft')
|
|
203
|
+
continue;
|
|
204
|
+
const daysSinceUpdate = scoring.updatedAt
|
|
205
|
+
? (now - new Date(scoring.updatedAt).getTime()) / (1000 * 60 * 60 * 24)
|
|
206
|
+
: 0;
|
|
207
|
+
const decayed = applyDecay(scoring, daysSinceUpdate);
|
|
208
|
+
if ((decayed.importance ?? 50) < ARCHIVE_IMPORTANCE_THRESHOLD) {
|
|
209
|
+
candidates.push(relativePath);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
// Skip unreadable files
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/* eslint-enable no-await-in-loop */
|
|
218
|
+
}
|
|
219
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-based implementation of IContextTreeManifestService.
|
|
3
|
+
*
|
|
4
|
+
* Builds and reads the context manifest (_manifest.json) which allocates
|
|
5
|
+
* context tree entries into three lanes (summaries, contexts, stubs)
|
|
6
|
+
* with token budgets for efficient query context injection.
|
|
7
|
+
*
|
|
8
|
+
* Freshness check uses source_fingerprint (hash of sorted path:mtime:size)
|
|
9
|
+
* to detect additions, modifications, and deletions. Stat-only, no file reads.
|
|
10
|
+
*
|
|
11
|
+
* Tradeoff: rare false-fresh cases where content changes but mtime+size
|
|
12
|
+
* are preserved. Acceptable because writeFile() updates mtime and the next
|
|
13
|
+
* curate run will rebuild the manifest anyway.
|
|
14
|
+
*/
|
|
15
|
+
import type { ContextManifest, LaneTokens, ResolvedEntry } from '../../core/domain/knowledge/summary-types.js';
|
|
16
|
+
import type { IContextTreeManifestService } from '../../core/interfaces/context-tree/i-context-tree-manifest-service.js';
|
|
17
|
+
export interface ManifestServiceConfig {
|
|
18
|
+
baseDirectory?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare class FileContextTreeManifestService implements IContextTreeManifestService {
|
|
21
|
+
private readonly config;
|
|
22
|
+
constructor(config?: ManifestServiceConfig);
|
|
23
|
+
buildManifest(directory?: string, laneBudgets?: LaneTokens): Promise<ContextManifest>;
|
|
24
|
+
readManifest(directory?: string): Promise<ContextManifest | null>;
|
|
25
|
+
readManifestIfFresh(directory?: string): Promise<ContextManifest | null>;
|
|
26
|
+
resolveForInjection(manifest: ContextManifest, _query?: string, directory?: string): Promise<ResolvedEntry[]>;
|
|
27
|
+
/**
|
|
28
|
+
* Allocate entries into a lane respecting the token budget.
|
|
29
|
+
* Entries are already sorted by priority (caller responsibility).
|
|
30
|
+
*/
|
|
31
|
+
private allocateLane;
|
|
32
|
+
/**
|
|
33
|
+
* Compute source fingerprint from stat data (path:mtime:size).
|
|
34
|
+
* Stat-only — no file reads required.
|
|
35
|
+
*/
|
|
36
|
+
private computeSourceFingerprint;
|
|
37
|
+
/**
|
|
38
|
+
* Recursively scan _archived/ directory for .stub.md files.
|
|
39
|
+
*/
|
|
40
|
+
private scanArchivedStubs;
|
|
41
|
+
/**
|
|
42
|
+
* Recursively scan context tree, collecting entries for manifest building.
|
|
43
|
+
*/
|
|
44
|
+
private scanForManifest;
|
|
45
|
+
/**
|
|
46
|
+
* Recursively collect stat data for all source files (for fingerprint).
|
|
47
|
+
* Excludes derived artifacts.
|
|
48
|
+
*/
|
|
49
|
+
private scanSourceStats;
|
|
50
|
+
}
|