Add Chinese documentation for custom skills development and reference guide

- Created a new document for custom skills development (`custom.md`) detailing the structure, creation, implementation, and best practices for developing custom CCW skills.
- Added an index document (`index.md`) summarizing all built-in skills, their categories, and usage examples.
- Introduced a reference guide (`reference.md`) providing a quick reference for all 33 built-in CCW skills, including triggers and purposes.
This commit is contained in:
catlog22
2026-03-01 13:08:12 +08:00
parent 2fb93d20e0
commit 8ceae6d6fd
78 changed files with 12352 additions and 3638 deletions

View File

@@ -60,5 +60,91 @@ describe('CsrfTokenManager', async () => {
assert.equal(manager.validateToken(token, 'session-1'), true);
manager.dispose();
});
// ========== Pool Pattern Tests ==========
it('generateTokens produces N unique tokens', () => {
const manager = new mod.CsrfTokenManager({ cleanupIntervalMs: 0, maxTokensPerSession: 5 });
const tokens = manager.generateTokens('session-1', 3);
assert.equal(tokens.length, 3);
// All tokens should be unique
assert.equal(new Set(tokens).size, 3);
// All tokens should be valid hex
for (const token of tokens) {
assert.match(token, /^[a-f0-9]{64}$/);
}
manager.dispose();
});
it('generateTokens respects maxTokensPerSession limit', () => {
const manager = new mod.CsrfTokenManager({ cleanupIntervalMs: 0, maxTokensPerSession: 5 });
// First batch of 5
const tokens1 = manager.generateTokens('session-1', 5);
assert.equal(tokens1.length, 5);
// Second batch should be empty (pool full)
const tokens2 = manager.generateTokens('session-1', 3);
assert.equal(tokens2.length, 0);
manager.dispose();
});
it('getTokenCount returns correct count for session', () => {
const manager = new mod.CsrfTokenManager({ cleanupIntervalMs: 0 });
manager.generateTokens('session-1', 3);
manager.generateTokens('session-2', 2);
assert.equal(manager.getTokenCount('session-1'), 3);
assert.equal(manager.getTokenCount('session-2'), 2);
assert.equal(manager.getTokenCount('session-3'), 0);
manager.dispose();
});
it('validateToken works with pool pattern (multiple tokens per session)', () => {
const manager = new mod.CsrfTokenManager({ cleanupIntervalMs: 0 });
const tokens = manager.generateTokens('session-1', 3);
// All tokens should be valid once
assert.equal(manager.validateToken(tokens[0], 'session-1'), true);
assert.equal(manager.validateToken(tokens[1], 'session-1'), true);
assert.equal(manager.validateToken(tokens[2], 'session-1'), true);
// All tokens should now be invalid (used)
assert.equal(manager.validateToken(tokens[0], 'session-1'), false);
assert.equal(manager.validateToken(tokens[1], 'session-1'), false);
assert.equal(manager.validateToken(tokens[2], 'session-1'), false);
manager.dispose();
});
it('cleanupExpiredTokens handles multiple sessions', () => {
const manager = new mod.CsrfTokenManager({ tokenTtlMs: 10, cleanupIntervalMs: 0 });
manager.generateTokens('session-1', 3);
manager.generateTokens('session-2', 2);
const removed = manager.cleanupExpiredTokens(Date.now() + 100);
assert.equal(removed, 5);
assert.equal(manager.getActiveTokenCount(), 0);
assert.equal(manager.getTokenCount('session-1'), 0);
assert.equal(manager.getTokenCount('session-2'), 0);
manager.dispose();
});
it('concurrent requests can use different tokens from pool', () => {
const manager = new mod.CsrfTokenManager({ cleanupIntervalMs: 0 });
const tokens = manager.generateTokens('session-1', 5);
// Simulate 5 concurrent requests using different tokens
const results = tokens.map(token => manager.validateToken(token, 'session-1'));
// All should succeed
assert.deepEqual(results, [true, true, true, true, true]);
// Token count should still be 5 (but all marked as used)
assert.equal(manager.getTokenCount('session-1'), 5);
manager.dispose();
});
});