Skip to content
Merged

dev #106

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ members = [
]

[workspace.package]
version = "2026.10328.106"
version = "2026.10329.110"
edition = "2024"
license = "AGPL-3.0-only"
authors = ["TrueNine"]
Expand Down
2 changes: 1 addition & 1 deletion cli/npm/darwin-arm64/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@truenine/memory-sync-cli-darwin-arm64",
"version": "2026.10328.106",
"version": "2026.10329.110",
"os": [
"darwin"
],
Expand Down
2 changes: 1 addition & 1 deletion cli/npm/darwin-x64/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@truenine/memory-sync-cli-darwin-x64",
"version": "2026.10328.106",
"version": "2026.10329.110",
"os": [
"darwin"
],
Expand Down
2 changes: 1 addition & 1 deletion cli/npm/linux-arm64-gnu/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@truenine/memory-sync-cli-linux-arm64-gnu",
"version": "2026.10328.106",
"version": "2026.10329.110",
"os": [
"linux"
],
Expand Down
2 changes: 1 addition & 1 deletion cli/npm/linux-x64-gnu/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@truenine/memory-sync-cli-linux-x64-gnu",
"version": "2026.10328.106",
"version": "2026.10329.110",
"os": [
"linux"
],
Expand Down
2 changes: 1 addition & 1 deletion cli/npm/win32-x64-msvc/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@truenine/memory-sync-cli-win32-x64-msvc",
"version": "2026.10328.106",
"version": "2026.10329.110",
"os": [
"win32"
],
Expand Down
15 changes: 10 additions & 5 deletions cli/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@truenine/memory-sync-cli",
"type": "module",
"version": "2026.10328.106",
"version": "2026.10329.110",
"description": "TrueNine Memory Synchronization CLI",
"author": "TrueNine",
"license": "AGPL-3.0-only",
Expand Down Expand Up @@ -51,18 +51,23 @@
"build": "run-s build:deps build:napi bundle finalize:bundle generate:schema",
"build:napi": "tsx ../scripts/copy-napi.ts",
"build:deps": "pnpm -F @truenine/logger -F @truenine/md-compiler -F @truenine/script-runtime run build",
"build:deps:ts": "pnpm -F @truenine/logger -F @truenine/md-compiler -F @truenine/script-runtime run build:ts",
"bundle": "tsx ../scripts/build-quiet.ts",
"check": "run-p typecheck lint",
"check": "run-s build:deps:ts check:run",
"check:run": "run-p lint:run typecheck:run",
"finalize:bundle": "tsx scripts/finalize-bundle.ts",
"generate:schema": "tsx scripts/generate-schema.ts",
"lint": "eslint --cache --cache-location node_modules/.cache/.eslintcache .",
"lint": "run-s build:deps:ts lint:run",
"lint:run": "eslint --cache --cache-location node_modules/.cache/.eslintcache .",
"prepublishOnly": "run-s build check",
"test": "run-s build:deps test:run",
"test:native-cleanup-smoke": "tsx scripts/cleanup-native-smoke.ts",
"test:run": "vitest run",
"benchmark:cleanup": "tsx scripts/benchmark-cleanup.ts",
"lintfix": "eslint --fix --cache --cache-location node_modules/.cache/.eslintcache .",
"typecheck": "tsc --noEmit -p tsconfig.lib.json"
"lintfix": "run-s build:deps:ts lintfix:run",
"lintfix:run": "eslint --fix --cache --cache-location node_modules/.cache/.eslintcache .",
"typecheck": "run-s build:deps:ts typecheck:run",
"typecheck:run": "tsc --noEmit -p tsconfig.lib.json"
},
"dependencies": {
"json5": "catalog:",
Expand Down
32 changes: 32 additions & 0 deletions cli/src/ConfigLoader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,36 @@ describe('configLoader', () => {
fs.rmSync(tempHome, {recursive: true, force: true})
}
})

it('defaults aindex.softwares when loading an older config file', () => {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'tnmsc-config-loader-'))
const configPath = path.join(tempDir, '.tnmsc.json')

try {
fs.writeFileSync(configPath, JSON.stringify({
workspaceDir: '/tmp/workspace',
aindex: {
dir: 'aindex',
skills: {src: 'skills', dist: 'dist/skills'},
commands: {src: 'commands', dist: 'dist/commands'},
subAgents: {src: 'subagents', dist: 'dist/subagents'},
rules: {src: 'rules', dist: 'dist/rules'},
globalPrompt: {src: 'global.src.mdx', dist: 'dist/global.mdx'},
workspacePrompt: {src: 'workspace.src.mdx', dist: 'dist/workspace.mdx'},
app: {src: 'app', dist: 'dist/app'},
ext: {src: 'ext', dist: 'dist/ext'},
arch: {src: 'arch', dist: 'dist/arch'}
}
}), 'utf8')

const loader = new ConfigLoader()
const result = loader.loadFromFile(configPath)

expect(result.found).toBe(true)
expect(result.config.aindex?.softwares).toEqual({src: 'softwares', dist: 'dist/softwares'})
}
finally {
fs.rmSync(tempDir, {recursive: true, force: true})
}
})
})
18 changes: 4 additions & 14 deletions cli/src/ConfigLoader.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import type {ILogger} from '@truenine/logger'
import type {
AindexConfig,
CleanupProtectionOptions,
ConfigLoaderOptions,
ConfigLoadResult,
FrontMatterOptions,
ILogger,
OutputScopeOptions,
PluginOutputScopeTopics,
UserConfigFile,
WindowsOptions
} from './plugins/plugin-core'
import * as fs from 'node:fs'
import process from 'node:process'
import {createLogger} from '@truenine/logger'
import {
buildConfigDiagnostic,
buildFileOperationDiagnostic,
diagnosticLines,
splitDiagnosticText
} from './diagnostics'
import {createLogger, ZUserConfigFile} from './plugins/plugin-core'
import {mergeAindexConfig, ZUserConfigFile} from './plugins/plugin-core'
import {
getRequiredGlobalConfigPath,
resolveRuntimeEnvironment,
Expand Down Expand Up @@ -189,18 +190,7 @@ export class ConfigLoader {
if (a == null && b == null) return void 0
if (a == null) return b
if (b == null) return a
return {
dir: b.dir ?? a.dir,
skills: {...a.skills, ...b.skills},
commands: {...a.commands, ...b.commands},
subAgents: {...a.subAgents, ...b.subAgents},
rules: {...a.rules, ...b.rules},
globalPrompt: {...a.globalPrompt, ...b.globalPrompt},
workspacePrompt: {...a.workspacePrompt, ...b.workspacePrompt},
app: {...a.app, ...b.app},
ext: {...a.ext, ...b.ext},
arch: {...a.arch, ...b.arch}
}
return mergeAindexConfig(a, b)
}

private mergeOutputScopeTopics(
Expand Down
31 changes: 16 additions & 15 deletions cli/src/ProtectedDeletionGuard.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import type {ILogger, OutputCollectedContext, PluginOptions} from './plugins/plugin-core'
import type {ILogger} from '@truenine/logger'
import type {OutputCollectedContext, PluginOptions} from './plugins/plugin-core'
import type {PublicDefinitionResolveOptions} from './public-config-paths'
import * as fs from 'node:fs'
import * as path from 'node:path'
import process from 'node:process'
import glob from 'fast-glob'
import {buildProtectedDeletionDiagnostic} from './diagnostics'
import {
AINDEX_CONFIG_DIRECTORY_PAIR_KEYS,
AINDEX_PROJECT_SERIES_NAMES
} from './plugins/plugin-core'
import {collectKnownPublicConfigDefinitionPaths} from './public-config-paths'
import {getEffectiveHomeDir, resolveUserPath} from './runtime-environment'

Expand Down Expand Up @@ -70,16 +75,6 @@ export class ProtectedDeletionGuardError extends Error {
}
}

const CONFIGURED_AINDEX_DIRECTORY_KEYS = [
'skills',
'commands',
'subAgents',
'rules',
'app',
'ext',
'arch'
] as const satisfies readonly (keyof Required<PluginOptions>['aindex'])[]

const CONFIGURED_AINDEX_FILE_KEYS = [
'globalPrompt',
'workspacePrompt'
Expand Down Expand Up @@ -291,7 +286,7 @@ function collectWorkspaceReservedRules(
'workspace-reserved',
'glob'
))
for (const seriesName of ['app', 'ext', 'arch'] as const) {
for (const seriesName of AINDEX_PROJECT_SERIES_NAMES) {
rules.push(createProtectedPathRule(
path.join(workspaceDir, 'aindex', seriesName, '**', '*.mdx'),
'direct',
Expand Down Expand Up @@ -321,10 +316,13 @@ export function collectConfiguredAindexInputRules(
): ProtectedPathRule[] {
const rules: ProtectedPathRule[] = []

for (const key of CONFIGURED_AINDEX_DIRECTORY_KEYS) {
for (const key of AINDEX_CONFIG_DIRECTORY_PAIR_KEYS) {
const configuredDir = pluginOptions.aindex[key]
if (configuredDir == null) continue

rules.push(
createProtectedPathRule(
path.join(aindexDir, pluginOptions.aindex[key].src),
path.join(aindexDir, configuredDir.src),
'recursive',
`configured aindex ${key} source directory`,
'configured-aindex-source'
Expand All @@ -333,9 +331,12 @@ export function collectConfiguredAindexInputRules(
}

for (const key of CONFIGURED_AINDEX_FILE_KEYS) {
const configuredFile = pluginOptions.aindex[key]
if (configuredFile == null) continue

rules.push(
createProtectedPathRule(
path.join(aindexDir, pluginOptions.aindex[key].src),
path.join(aindexDir, configuredFile.src),
'direct',
`configured aindex ${key} source file`,
'configured-aindex-source'
Expand Down
10 changes: 9 additions & 1 deletion cli/src/commands/Command.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import type {ILogger, LoggerDiagnosticRecord, OutputCleanContext, OutputCollectedContext, OutputPlugin, OutputWriteContext, PluginOptions, UserConfigFile} from '../plugins/plugin-core'
import type {ILogger, LoggerDiagnosticRecord} from '@truenine/logger'
import type {
OutputCleanContext,
OutputCollectedContext,
OutputPlugin,
OutputWriteContext,
PluginOptions,
UserConfigFile
} from '../plugins/plugin-core'

/**
* Command execution context
Expand Down
29 changes: 7 additions & 22 deletions cli/src/commands/ConfigCommand.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,22 @@
import type {Command, CommandContext, CommandResult} from './Command'
import type {AindexConfigKeyPath} from '@/plugins/plugin-core'
import * as fs from 'node:fs'
import * as path from 'node:path'
import {buildUsageDiagnostic, diagnosticLines} from '@/diagnostics'
import {AINDEX_CONFIG_KEY_PATHS} from '@/plugins/plugin-core'
import {getRequiredGlobalConfigPath} from '@/runtime-environment'

/**
* Valid configuration keys that can be set via `tnmsc config key=value`.
* Nested keys use dot-notation: aindex.skills.src, aindex.commands.src, etc.
*/
const VALID_CONFIG_KEYS = [
type ValidConfigKey = 'workspaceDir' | 'logLevel' | AindexConfigKeyPath

const VALID_CONFIG_KEYS: readonly ValidConfigKey[] = [
'workspaceDir',
'aindex.skills.src',
'aindex.skills.dist',
'aindex.commands.src',
'aindex.commands.dist',
'aindex.subAgents.src',
'aindex.subAgents.dist',
'aindex.rules.src',
'aindex.rules.dist',
'aindex.globalPrompt.src',
'aindex.globalPrompt.dist',
'aindex.workspacePrompt.src',
'aindex.workspacePrompt.dist',
'aindex.app.src',
'aindex.app.dist',
'aindex.ext.src',
'aindex.ext.dist',
'aindex.arch.src',
'aindex.arch.dist',
...AINDEX_CONFIG_KEY_PATHS,
'logLevel'
] as const

type ValidConfigKey = typeof VALID_CONFIG_KEYS[number]
]

/**
* Validate if a key is a valid config key
Expand Down
13 changes: 3 additions & 10 deletions cli/src/commands/HelpCommand.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type {Command, CommandContext, CommandResult} from './Command'
import {AINDEX_CONFIG_KEY_PATHS} from '@/plugins/plugin-core'
import {getCliVersion} from './VersionCommand'

const CLI_NAME = 'tnmsc'
const CONFIG_KEY_LIST_TEXT = ['workspaceDir', 'logLevel', ...AINDEX_CONFIG_KEY_PATHS].join(',\n ')

const HELP_TEXT = `
${CLI_NAME} v${getCliVersion()} - Memory Sync CLI
Expand Down Expand Up @@ -44,16 +46,7 @@ CLEAN OPTIONS:

CONFIG OPTIONS:
key=value Set a configuration value in global config (~/.aindex/.tnmsc.json)
Valid keys: workspaceDir, logLevel,
aindex.skills.src, aindex.skills.dist,
aindex.commands.src, aindex.commands.dist,
aindex.subAgents.src, aindex.subAgents.dist,
aindex.rules.src, aindex.rules.dist,
aindex.globalPrompt.src, aindex.globalPrompt.dist,
aindex.workspacePrompt.src, aindex.workspacePrompt.dist,
aindex.app.src, aindex.app.dist,
aindex.ext.src, aindex.ext.dist,
aindex.arch.src, aindex.arch.dist
Valid keys: ${CONFIG_KEY_LIST_TEXT}

Examples:
${CLI_NAME} config workspaceDir=~/my-project
Expand Down
Loading
Loading