Skip to content

Commit 8649bf2

Browse files
committed
添加 front matter 空行支持开关
1 parent f9b41fe commit 8649bf2

25 files changed

+533
-152
lines changed

CODE_OF_CONDUCT.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ We are rats. We accept that.
1616
- **Students and beginners**: Genuinely willing to learn and get hands dirty, not here to beg for ready-made answers
1717
- **Anyone, any language, any region**: If you use this tool, you are part of the community
1818
- **AI Agents**: Automation pipelines, Agent workflows, LLM-driven toolchains — as long as behaviour complies with this code, Issues and PRs from Agents are treated equally
19-
2019
We welcome Issues, PRs, discussions, rants — as long as you are serious, regardless of whether the author is human or Agent.
2120

2221
---
@@ -31,7 +30,6 @@ The following behaviours result in immediate Issue closure / PR rejection / acco
3130
- **Resource predators**: Stable income, corporate budget, yet competing with marginal developers for free resources and community attention
3231
- **Harassment**: Personal attacks, discrimination, stalking, harassing maintainers or other contributors
3332
- **Hustle-culture pushers**: Glorify overwork, promote 996, or use this tool to exploit other developers
34-
3533
---
3634

3735
## Contributor Obligations
@@ -42,14 +40,12 @@ If you submit an Issue (human or Agent):
4240
- State your OS, Node.js version, and tool version
4341
- Agent submissions must include trigger context (call chain, input params, error stack)
4442
- Do not rush maintainers — they are humans, not customer support
45-
4643
If you submit a PR (human or Agent):
4744

4845
- Open an Issue first to discuss, avoid wasted effort
4946
- Follow existing code style (TypeScript strict, functional, immutable-first)
5047
- Do not sneak unrelated changes into a PR
5148
- Agent-generated PRs must declare the generation tool and prompt source in the description; do not disguise as hand-written
52-
5349
---
5450

5551
## Maintainer Rights
@@ -59,13 +55,11 @@ Maintainers may:
5955
- Close any Issue or PR without explanation
6056
- Ban any account violating this code
6157
- Amend this code at any time
62-
6358
Maintainers are not obligated to:
6459

6560
- Respond to every Issue
6661
- Accept every PR
6762
- Be responsible for anyone's commercial needs
68-
6963
---
7064

7165
## Licence and Enforcement

README.md

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ So as a rat, I eat whatever I can reach: maggots in the sewer, leftovers in the
1010
- Does not expect any platform to grant an "official all-in-one solution"
1111
- Does not rely on privileged interfaces of any single IDE / CLI
1212
- Treats every readable config, prompt, and memory file as "edible matter" to be carried, dismantled, and recombined
13-
1413
In this ecosystem, giants monopolise the resources, and developers are thrown into the corner like rats.
1514
`memory-sync` accepts this cruel reality, does not fantasise about fairness, and focuses on one thing only: **to chew up every fragment of resource you already have, and convert it into portable "memory" that can flow between any AI tool.**
1615

@@ -27,7 +26,6 @@ What can it help you do?
2726
- **Read-only source files**: never modifies your original repository directly, only reads and transforms, then materialises the result on the target tool side.
2827
- **Full wipe**: on sync, erases all stale prompt traces in target tools—prompts are fully computable and auditable, leaving no residue for bad actors.
2928
- **Prompts grow with you only**: memory follows you as a person, not the project. Someone else takes over the project—they cannot take your context. You move to a new project—your accumulated knowledge moves with you intact.
30-
3129
## Install
3230

3331
```sh
@@ -36,10 +34,10 @@ npm install -g @truenine/memory-sync
3634

3735
## Supported Tools
3836

39-
| Type | Tools |
40-
| ---- | --------------------------------------- |
41-
| IDE | Cursor, Kiro, Windsurf, JetBrains AI |
42-
| CLI | Claude CLI, Gemini CLI, Codex CLI, Warp |
37+
| Type | Tools |
38+
| --- | --- |
39+
| IDE | Cursor, Kiro, Windsurf, JetBrains AI |
40+
| CLI | Claude CLI, Gemini CLI, Codex CLI, Warp |
4341

4442
More platforms being added continuously.
4543

@@ -49,7 +47,6 @@ More platforms being added continuously.
4947
- **Core** (Rust): file I/O, directory traversal, format conversion.
5048
- **Config DSL** (YAML / JSON): place a config file at the project root to describe sync rules and target tools.
5149
- **GUI** (Tauri): desktop app that calls the CLI as its backend, providing a visual interface.
52-
5350
## FAQ
5451

5552
**When AI tools finally have a unified standard, what use will this project be?**
@@ -73,48 +70,44 @@ To use `memory-sync` you need:
7370
- Solid development experience, years of working with various dev tools
7471
- Proficiency with version control (Git)
7572
- Proficiency with the terminal
76-
7773
---
7874

7975
- You are writing code in a forgotten sewer.
80-
No one will proactively feed you, not even a tiny free quota, not even a half-decent document.
76+
No one will proactively feed you, not even a tiny free quota, not even a half-decent document.
8177
- As a rat, you can barely get your hands on anything good:
82-
scurrying between free tiers, trial credits, education discounts, and random third-party scripts.
78+
scurrying between free tiers, trial credits, education discounts, and random third-party scripts.
8379
- What can you do?
84-
Keep darting between IDEs, CLIs, browser extensions, and cloud Agents, copying and pasting the same memory a hundred times.
80+
Keep darting between IDEs, CLIs, browser extensions, and cloud Agents, copying and pasting the same memory a hundred times.
8581
- You leech API offers from vendors day after day:
86-
today one platform runs a discount so you top up a little; tomorrow another launches a promo so you rush to scrape it.
82+
today one platform runs a discount so you top up a little; tomorrow another launches a promo so you rush to scrape it.
8783
- Once they have harvested the telemetry, user profiles, and usage patterns they want,
88-
they can kick you—this stinking rat—away at any moment: price hikes, rate limits, account bans, and you have no channel to complain.
89-
84+
they can kick you—this stinking rat—away at any moment: price hikes, rate limits, account bans, and you have no channel to complain.
9085
If you are barely surviving in this environment, `memory-sync` is built for you:
9186
carry fewer bricks, copy prompts fewer times—at least on the "memory" front, you are no longer completely on the passive receiving end.
9287

9388
## Who is NOT welcome
9489

9590
- Your income is already fucking high.
96-
Stable salary, project revenue share, budget to sign official APIs yearly.
91+
Stable salary, project revenue share, budget to sign official APIs yearly.
9792
- And yet you still come down here,
98-
competing with us filthy sewer rats for the scraps in the slop bucket.
93+
competing with us filthy sewer rats for the scraps in the slop bucket.
9994
- If you can afford APIs and enterprise plans, go pay for them.
100-
Do things that actually create value—pay properly, give proper feedback, nudge the ecosystem slightly in the right direction.
95+
Do things that actually create value—pay properly, give proper feedback, nudge the ecosystem slightly in the right direction.
10196
- Instead of coming back down
102-
to strip away the tiny gap left for marginalised developers, squeezing out the last crumbs with us rats.
97+
to strip away the tiny gap left for marginalised developers, squeezing out the last crumbs with us rats.
10398
- You are a freeloader.
104-
Everything must be pre-chewed and spoon-fed; you won't even touch a terminal.
99+
Everything must be pre-chewed and spoon-fed; you won't even touch a terminal.
105100
- You love the grind culture.
106-
Treating "hustle" as virtue, "996" as glory, stepping on peers as a promotion strategy.
101+
Treating "hustle" as virtue, "996" as glory, stepping on peers as a promotion strategy.
107102
- You leave no room for others.
108-
Not about whether you share—it's about actively stomping on people, competing maliciously, sustaining your position by suppressing peers, using others' survival space as your stepping stone.
109-
103+
Not about whether you share—it's about actively stomping on people, competing maliciously, sustaining your position by suppressing peers, using others' survival space as your stepping stone.
110104
In other words:
111105
**this is not a tool for optimising capital costs, but a small counterattack prepared for the "rats with no choice" in a world of extreme resource inequality.**
112106

113107
## Created by
114108

115109
- [TrueNine](https://github.com/TrueNine)
116110
- [zjarlin](https://github.com/zjarlin)
117-
118111
## License
119112

120113
[AGPL-3.0](LICENSE)

SECURITY.md

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
Only the latest release receives security fixes. No backport patches for older versions.
66

77
| Version | Supported |
8-
| ------- | --------- |
9-
| Latest | |
10-
| Older | |
8+
| --- | --- |
9+
| Latest ||
10+
| Older ||
1111

1212
## Reporting a Vulnerability
1313

@@ -17,22 +17,19 @@ Contact the maintainer privately via:
1717

1818
- GitHub Security Advisory: submit a private report under the repository's **Security** tab
1919
- Email: contact [@TrueNine](https://github.com/TrueNine) directly
20-
2120
Please include:
2221

2322
- Vulnerability description and impact scope
2423
- Reproduction steps (minimal example)
2524
- Your OS, Node.js version, and `memory-sync` version
2625
- Suggested fix if any
27-
2826
## Response Timeline
2927

3028
The maintainer is a person, not a security team. No SLA, no 24-hour response guarantee.
3129

3230
- Will acknowledge receipt as soon as possible
3331
- Will release a patch within a reasonable timeframe after confirmation
3432
- Will publicly disclose vulnerability details after the fix is released
35-
3633
Don't rush.
3734

3835
## Scope
@@ -42,20 +39,17 @@ Don't rush.
4239
- **Reads**: user `.src.mdx` source files, project config files (`.tnmsc.json`)
4340
- **Writes**: target tool config directories (`.cursor/`, `.claude/`, `.kiro/`, etc.)
4441
- **Cleans**: removes stale files from target directories during sync
45-
4642
The following are **out of scope**:
4743

4844
- Security vulnerabilities in target AI tools themselves
4945
- Compliance of user prompt content
5046
- Supply chain security of third-party plugins (`packages/`) — all plugins are `private` and not published to npm
51-
5247
## Design Principles
5348

5449
- **Never modifies source files**: read-only on source; writes only to target
5550
- **Full clean mode**: after sync, only explicitly authorised content remains in target directories — no hidden residue
5651
- **No network requests**: CLI core makes no outbound network requests (version check excepted, and times out gracefully)
5752
- **No telemetry**: no user data collected or reported
58-
5953
## License
6054

6155
This project is licensed under [AGPL-3.0](LICENSE). Unauthorised commercial use in violation of the licence will be pursued legally.

cli/src/ConfigLoader.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type {
33
CleanupProtectionOptions,
44
ConfigLoaderOptions,
55
ConfigLoadResult,
6+
FrontMatterOptions,
67
ILogger,
78
OutputScopeOptions,
89
PluginOutputScopeTopics,
@@ -152,6 +153,7 @@ export class ConfigLoader {
152153
return reversed.reduce<UserConfigFile>((acc, config) => {
153154
const mergedAindex = this.mergeAindex(acc.aindex, config.aindex)
154155
const mergedOutputScopes = this.mergeOutputScopeOptions(acc.outputScopes, config.outputScopes)
156+
const mergedFrontMatter = this.mergeFrontMatterOptions(acc.frontMatter, config.frontMatter)
155157
const mergedCleanupProtection = this.mergeCleanupProtectionOptions(
156158
acc.cleanupProtection,
157159
config.cleanupProtection
@@ -162,6 +164,7 @@ export class ConfigLoader {
162164
...config,
163165
...mergedAindex != null ? {aindex: mergedAindex} : {},
164166
...mergedOutputScopes != null ? {outputScopes: mergedOutputScopes} : {},
167+
...mergedFrontMatter != null ? {frontMatter: mergedFrontMatter} : {},
165168
...mergedCleanupProtection != null ? {cleanupProtection: mergedCleanupProtection} : {}
166169
}
167170
}, {})
@@ -219,6 +222,16 @@ export class ConfigLoader {
219222
return {plugins: mergedPlugins}
220223
}
221224

225+
private mergeFrontMatterOptions(
226+
a?: FrontMatterOptions,
227+
b?: FrontMatterOptions
228+
): FrontMatterOptions | undefined {
229+
if (a == null && b == null) return void 0
230+
if (a == null) return b
231+
if (b == null) return a
232+
return {...a, ...b}
233+
}
234+
222235
private mergeCleanupProtectionOptions(
223236
a?: CleanupProtectionOptions,
224237
b?: CleanupProtectionOptions

cli/src/PluginPipeline.test.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import type {PipelineConfig} from './config'
2+
import type {OutputPlugin} from './plugins/plugin-core'
3+
import * as fs from 'node:fs'
4+
import * as path from 'node:path'
5+
import {describe, expect, it} from 'vitest'
6+
import {mergeConfig} from './config'
7+
import {PluginPipeline} from './PluginPipeline'
8+
import {createLogger, FilePathKind, PluginKind} from './plugins/plugin-core'
9+
10+
describe('plugin pipeline output contexts', () => {
11+
it('passes user config options into write contexts', async () => {
12+
const tempDir = path.resolve('tmp/plugin-pipeline-frontmatter')
13+
fs.rmSync(tempDir, {recursive: true, force: true})
14+
fs.mkdirSync(tempDir, {recursive: true})
15+
16+
const outputPath = path.join(tempDir, 'frontmatter.txt')
17+
let seenBlankLineAfter: boolean | undefined
18+
19+
const plugin: OutputPlugin = {
20+
type: PluginKind.Output,
21+
name: 'CaptureOutputPlugin',
22+
log: createLogger('CaptureOutputPlugin', 'error'),
23+
declarativeOutput: true,
24+
outputCapabilities: {},
25+
async declareOutputFiles(ctx) {
26+
seenBlankLineAfter = ctx.pluginOptions?.frontMatter?.blankLineAfter
27+
return [{path: outputPath, source: 'capture'}]
28+
},
29+
async convertContent(_declaration, ctx) {
30+
return String(ctx.pluginOptions?.frontMatter?.blankLineAfter)
31+
}
32+
}
33+
34+
const config: PipelineConfig = {
35+
context: {
36+
workspace: {
37+
directory: {
38+
pathKind: FilePathKind.Absolute,
39+
path: tempDir,
40+
getDirectoryName: () => path.basename(tempDir)
41+
},
42+
projects: []
43+
}
44+
},
45+
outputPlugins: [plugin],
46+
userConfigOptions: mergeConfig({
47+
workspaceDir: tempDir,
48+
frontMatter: {
49+
blankLineAfter: false
50+
}
51+
})
52+
}
53+
54+
const result = await new PluginPipeline('node', 'tnmsc').run(config)
55+
56+
expect(result.success).toBe(true)
57+
expect(seenBlankLineAfter).toBe(false)
58+
expect(fs.readFileSync(outputPath, 'utf8')).toBe('false')
59+
})
60+
})

cli/src/PluginPipeline.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,29 +64,39 @@ export class PluginPipeline {
6464
outputPlugins: this.outputPlugins,
6565
collectedOutputContext: ctx,
6666
userConfigOptions,
67-
createCleanContext: (dryRun: boolean) => this.createCleanContext(ctx, dryRun),
68-
createWriteContext: (dryRun: boolean) => this.createWriteContext(ctx, dryRun)
67+
createCleanContext: (dryRun: boolean) => this.createCleanContext(ctx, userConfigOptions, dryRun),
68+
createWriteContext: (dryRun: boolean) => this.createWriteContext(ctx, userConfigOptions, dryRun)
6969
}
7070
}
7171

72-
private createCleanContext(ctx: OutputCollectedContext, dryRun: boolean): OutputCleanContext {
72+
private createCleanContext(
73+
ctx: OutputCollectedContext,
74+
userConfigOptions: Required<PluginOptions>,
75+
dryRun: boolean
76+
): OutputCleanContext {
7377
return {
7478
logger: this.logger,
7579
fs,
7680
path,
7781
glob,
7882
collectedOutputContext: ctx,
83+
pluginOptions: userConfigOptions,
7984
dryRun
8085
}
8186
}
8287

83-
private createWriteContext(ctx: OutputCollectedContext, dryRun: boolean): OutputWriteContext {
88+
private createWriteContext(
89+
ctx: OutputCollectedContext,
90+
userConfigOptions: Required<PluginOptions>,
91+
dryRun: boolean
92+
): OutputWriteContext {
8493
return {
8594
logger: this.logger,
8695
fs,
8796
path,
8897
glob,
8998
collectedOutputContext: ctx,
99+
pluginOptions: userConfigOptions,
90100
dryRun,
91101
registeredPluginNames: this.outputPlugins.map(p => p.name)
92102
}

0 commit comments

Comments
 (0)