Skip to content

Commit 4456bdc

Browse files
authored
Merge pull request #100 from TrueNine/dev
feat: add desk path runtime support
2 parents 3d685d6 + eb11920 commit 4456bdc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2208
-662
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ members = [
99
]
1010

1111
[workspace.package]
12-
version = "2026.10324.11958"
12+
version = "2026.10325.12228"
1313
edition = "2024"
1414
license = "AGPL-3.0-only"
1515
authors = ["TrueNine"]

cli/npm/darwin-arm64/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@truenine/memory-sync-cli-darwin-arm64",
3-
"version": "2026.10324.11958",
3+
"version": "2026.10325.12228",
44
"os": [
55
"darwin"
66
],

cli/npm/darwin-x64/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@truenine/memory-sync-cli-darwin-x64",
3-
"version": "2026.10324.11958",
3+
"version": "2026.10325.12228",
44
"os": [
55
"darwin"
66
],

cli/npm/linux-arm64-gnu/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@truenine/memory-sync-cli-linux-arm64-gnu",
3-
"version": "2026.10324.11958",
3+
"version": "2026.10325.12228",
44
"os": [
55
"linux"
66
],

cli/npm/linux-x64-gnu/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@truenine/memory-sync-cli-linux-x64-gnu",
3-
"version": "2026.10324.11958",
3+
"version": "2026.10325.12228",
44
"os": [
55
"linux"
66
],

cli/npm/win32-x64-msvc/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@truenine/memory-sync-cli-win32-x64-msvc",
3-
"version": "2026.10324.11958",
3+
"version": "2026.10325.12228",
44
"os": [
55
"win32"
66
],

cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@truenine/memory-sync-cli",
33
"type": "module",
4-
"version": "2026.10324.11958",
4+
"version": "2026.10325.12228",
55
"description": "TrueNine Memory Synchronization CLI",
66
"author": "TrueNine",
77
"license": "AGPL-3.0-only",

cli/src/cleanup/delete-targets.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import * as path from 'node:path'
2+
import {resolveAbsolutePath} from '../ProtectedDeletionGuard'
3+
4+
export interface CompactedDeletionTargets {
5+
readonly files: string[]
6+
readonly dirs: string[]
7+
}
8+
9+
function stripTrailingSeparator(rawPath: string): string {
10+
const {root} = path.parse(rawPath)
11+
if (rawPath === root) return rawPath
12+
return rawPath.endsWith(path.sep) ? rawPath.slice(0, -1) : rawPath
13+
}
14+
15+
export function isSameOrChildDeletionPath(candidate: string, parent: string): boolean {
16+
const normalizedCandidate = stripTrailingSeparator(candidate)
17+
const normalizedParent = stripTrailingSeparator(parent)
18+
if (normalizedCandidate === normalizedParent) return true
19+
return normalizedCandidate.startsWith(`${normalizedParent}${path.sep}`)
20+
}
21+
22+
export function compactDeletionTargets(
23+
files: readonly string[],
24+
dirs: readonly string[]
25+
): CompactedDeletionTargets {
26+
const filesByKey = new Map<string, string>()
27+
const dirsByKey = new Map<string, string>()
28+
29+
for (const filePath of files) {
30+
const resolvedPath = resolveAbsolutePath(filePath)
31+
filesByKey.set(resolvedPath, resolvedPath)
32+
}
33+
34+
for (const dirPath of dirs) {
35+
const resolvedPath = resolveAbsolutePath(dirPath)
36+
dirsByKey.set(resolvedPath, resolvedPath)
37+
}
38+
39+
const compactedDirs = new Map<string, string>()
40+
const sortedDirEntries = [...dirsByKey.entries()].sort((a, b) => a[0].length - b[0].length)
41+
42+
for (const [dirKey, dirPath] of sortedDirEntries) {
43+
let coveredByParent = false
44+
for (const existingParentKey of compactedDirs.keys()) {
45+
if (isSameOrChildDeletionPath(dirKey, existingParentKey)) {
46+
coveredByParent = true
47+
break
48+
}
49+
}
50+
51+
if (!coveredByParent) compactedDirs.set(dirKey, dirPath)
52+
}
53+
54+
const compactedFiles: string[] = []
55+
for (const [fileKey, filePath] of filesByKey) {
56+
let coveredByDir = false
57+
for (const dirKey of compactedDirs.keys()) {
58+
if (isSameOrChildDeletionPath(fileKey, dirKey)) {
59+
coveredByDir = true
60+
break
61+
}
62+
}
63+
64+
if (!coveredByDir) compactedFiles.push(filePath)
65+
}
66+
67+
compactedFiles.sort((a, b) => a.localeCompare(b))
68+
const compactedDirPaths = [...compactedDirs.values()].sort((a, b) => a.localeCompare(b))
69+
70+
return {files: compactedFiles, dirs: compactedDirPaths}
71+
}

cli/src/commands/CleanupUtils.test.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,22 @@ function createMockLogger(): ILogger {
2323
} as ILogger
2424
}
2525

26+
function createRecordingLogger(): ILogger & {debugMessages: unknown[]} {
27+
const debugMessages: unknown[] = []
28+
29+
return {
30+
debugMessages,
31+
trace: () => {},
32+
debug: message => {
33+
debugMessages.push(message)
34+
},
35+
info: () => {},
36+
warn: () => {},
37+
error: () => {},
38+
fatal: () => {}
39+
} as ILogger & {debugMessages: unknown[]}
40+
}
41+
2642
function createCleanContext(
2743
overrides?: Partial<OutputCleanContext['collectedOutputContext']>,
2844
pluginOptionsOverrides?: Parameters<typeof mergeConfig>[0]
@@ -630,4 +646,47 @@ describe('performCleanup', () => {
630646
fs.rmSync(tempDir, {recursive: true, force: true})
631647
}
632648
})
649+
650+
it('logs aggregated cleanup execution summaries instead of per-path success logs', async () => {
651+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'tnmsc-perform-cleanup-logging-'))
652+
const outputFile = path.join(tempDir, 'project-a', 'AGENTS.md')
653+
const outputDir = path.join(tempDir, '.codex', 'prompts')
654+
const stalePrompt = path.join(outputDir, 'demo.md')
655+
const logger = createRecordingLogger()
656+
657+
fs.mkdirSync(path.dirname(outputFile), {recursive: true})
658+
fs.mkdirSync(outputDir, {recursive: true})
659+
fs.writeFileSync(outputFile, '# agent', 'utf8')
660+
fs.writeFileSync(stalePrompt, '# prompt', 'utf8')
661+
662+
try {
663+
const ctx = createCleanContext({
664+
workspace: {
665+
directory: {
666+
pathKind: FilePathKind.Absolute,
667+
path: tempDir,
668+
getDirectoryName: () => path.basename(tempDir),
669+
getAbsolutePath: () => tempDir
670+
},
671+
projects: []
672+
}
673+
})
674+
const plugin = createMockOutputPlugin('MockOutputPlugin', [outputFile], {
675+
delete: [{kind: 'directory', path: outputDir}]
676+
})
677+
678+
await performCleanup([plugin], ctx, logger)
679+
680+
expect(logger.debugMessages).toEqual(expect.arrayContaining([
681+
'cleanup plan built',
682+
'cleanup delete execution started',
683+
'cleanup delete execution complete'
684+
]))
685+
expect(logger.debugMessages).not.toContainEqual(expect.objectContaining({path: outputFile}))
686+
expect(logger.debugMessages).not.toContainEqual(expect.objectContaining({path: outputDir}))
687+
}
688+
finally {
689+
fs.rmSync(tempDir, {recursive: true, force: true})
690+
}
691+
})
633692
})

0 commit comments

Comments
 (0)