fluffy-context 0.5.0 → 0.7.2
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 +121 -9
- package/dist/src/agent/api.d.ts +5 -1
- package/dist/src/agent/api.js +41 -12
- package/dist/src/agent/index.d.ts +3 -1
- package/dist/src/agent/index.js +1 -0
- package/dist/src/agent/types.d.ts +21 -0
- package/dist/src/cli/main.js +150 -12
- package/dist/src/cognition/feedback.d.ts +9 -0
- package/dist/src/cognition/feedback.js +30 -0
- package/dist/src/cognition/filesystem-observer.d.ts +41 -0
- package/dist/src/cognition/filesystem-observer.js +164 -0
- package/dist/src/cognition/git-observer.d.ts +1 -0
- package/dist/src/cognition/git-observer.js +3 -2
- package/dist/src/cognition/journal.d.ts +4 -1
- package/dist/src/cognition/journal.js +83 -4
- package/dist/src/cognition/migration-v1.js +13 -11
- package/dist/src/cognition/orient.d.ts +4 -0
- package/dist/src/cognition/orient.js +14 -4
- package/dist/src/cognition/policy.d.ts +4 -0
- package/dist/src/cognition/policy.js +49 -0
- package/dist/src/cognition/projections.js +0 -0
- package/dist/src/cognition/retrieval.d.ts +26 -0
- package/dist/src/cognition/retrieval.js +273 -0
- package/dist/src/cognition/runtime.d.ts +20 -1
- package/dist/src/cognition/runtime.js +229 -53
- package/dist/src/cognition/types.d.ts +55 -1
- package/dist/src/cognition/v1-bridge.js +13 -4
- package/dist/src/compiler/activity.d.ts +3 -0
- package/dist/src/compiler/activity.js +79 -0
- package/dist/src/compiler/compile.d.ts +2 -0
- package/dist/src/compiler/compile.js +330 -0
- package/dist/src/compiler/sources.d.ts +19 -0
- package/dist/src/compiler/sources.js +130 -0
- package/dist/src/compiler/types.d.ts +187 -0
- package/dist/src/compiler/types.js +1 -0
- package/dist/src/hooks/claude-code.js +7 -15
- package/dist/src/mcp/main.js +2 -0
- package/dist/src/mcp/server.js +2 -0
- package/dist/src/runtime/knowledge.d.ts +2 -0
- package/dist/src/runtime/knowledge.js +63 -0
- package/dist/src/runtime/types.d.ts +19 -0
- package/dist/src/storage/layout.d.ts +2 -0
- package/dist/src/storage/layout.js +6 -0
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/package.json +2 -2
- package/skills/fluffy-context/SKILL.md +2 -1
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { contextOrient } from '../agent/api.js';
|
|
2
2
|
import { appendEvent } from '../cognition/journal.js';
|
|
3
3
|
import { v2Enabled } from '../cognition/orient.js';
|
|
4
|
-
import {
|
|
4
|
+
import { ensureRuntimeForSession, touchRuntime } from '../cognition/runtime.js';
|
|
5
|
+
import { loadRuntimePolicy } from '../cognition/policy.js';
|
|
5
6
|
import { readGitWorktreeState } from '../git/git-adapter.js';
|
|
6
7
|
import { resolveProjectRoot } from '../project/project-resolver.js';
|
|
7
|
-
import { cognitionPolicyPath } from '../storage/layout.js';
|
|
8
|
-
import { readJson } from '../storage/json-store.js';
|
|
9
8
|
const HOOK_RESPONSE = '{}\n';
|
|
10
9
|
function text(value) {
|
|
11
10
|
return typeof value === 'string' ? value : undefined;
|
|
@@ -68,15 +67,12 @@ function redactIntent(value) {
|
|
|
68
67
|
.replace(/\b(?:sk|ghp|gho|github_pat)_[A-Za-z0-9_-]+\b/g, () => { redactionCount += 1; return '[REDACTED]'; });
|
|
69
68
|
return { intent, redactionCount };
|
|
70
69
|
}
|
|
71
|
-
async function within(task, milliseconds) {
|
|
72
|
-
return Promise.race([task, new Promise((_, reject) => setTimeout(() => reject(new Error('hook deadline exceeded')), milliseconds))]);
|
|
73
|
-
}
|
|
74
70
|
async function capture(event, input) {
|
|
75
71
|
const cwd = text(input.cwd);
|
|
76
72
|
const projectRoot = await resolveProjectRoot(cwd);
|
|
77
73
|
if (!await v2Enabled(projectRoot))
|
|
78
74
|
return;
|
|
79
|
-
const policy = await
|
|
75
|
+
const policy = await loadRuntimePolicy(projectRoot);
|
|
80
76
|
const sessionId = stableId(input, 'session');
|
|
81
77
|
const eventId = stableId(input, 'event');
|
|
82
78
|
if (!sessionId || !eventId)
|
|
@@ -94,12 +90,7 @@ async function capture(event, input) {
|
|
|
94
90
|
});
|
|
95
91
|
}
|
|
96
92
|
async function maybeStartRuntime(input) {
|
|
97
|
-
|
|
98
|
-
if (!await v2Enabled(projectRoot))
|
|
99
|
-
return;
|
|
100
|
-
const policy = await readJson(cognitionPolicyPath(projectRoot));
|
|
101
|
-
if (policy.allowHookStartup)
|
|
102
|
-
await within(startRuntime(projectRoot), 1_000);
|
|
93
|
+
await ensureRuntimeForSession(text(input.cwd), { source: 'claude-hook', timeoutMs: 1_000 });
|
|
103
94
|
}
|
|
104
95
|
async function parseInput(raw) {
|
|
105
96
|
try {
|
|
@@ -115,9 +106,10 @@ export async function runClaudeCodeHook(event, raw) {
|
|
|
115
106
|
if (!input)
|
|
116
107
|
return HOOK_RESPONSE;
|
|
117
108
|
try {
|
|
118
|
-
|
|
119
|
-
|
|
109
|
+
await maybeStartRuntime(input).catch(() => undefined);
|
|
110
|
+
await touchRuntime(text(input.cwd)).catch(() => false);
|
|
120
111
|
await capture(event, input).catch(() => undefined);
|
|
112
|
+
await touchRuntime(text(input.cwd)).catch(() => false);
|
|
121
113
|
const cwd = text(input.cwd);
|
|
122
114
|
const result = event === 'session-start'
|
|
123
115
|
? await contextOrient(cwd, { maxChars: 1200, noteLimit: 8 })
|
package/dist/src/mcp/main.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { serveStdio } from '@modelcontextprotocol/server/stdio';
|
|
2
|
+
import { ensureRuntimeForSession } from '../cognition/runtime.js';
|
|
2
3
|
import { createMcpServer } from './server.js';
|
|
4
|
+
await ensureRuntimeForSession(process.cwd(), { source: 'mcp', timeoutMs: 1_000 }).catch(() => undefined);
|
|
3
5
|
serveStdio(createMcpServer, {
|
|
4
6
|
onerror: (error) => process.stderr.write(`MCP server error: ${error.message}\n`),
|
|
5
7
|
});
|
package/dist/src/mcp/server.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { contextOrient } from '../agent/api.js';
|
|
4
|
+
import { ensureRuntimeForSession } from '../cognition/runtime.js';
|
|
4
5
|
import { VERSION } from '../version.js';
|
|
5
6
|
const orientInput = z.object({
|
|
6
7
|
path: z.string().optional(),
|
|
@@ -23,6 +24,7 @@ export function createMcpServer() {
|
|
|
23
24
|
inputSchema: orientInput,
|
|
24
25
|
}, async ({ path, ...options }) => {
|
|
25
26
|
try {
|
|
27
|
+
await ensureRuntimeForSession(path, { source: 'mcp', timeoutMs: 1_000 }).catch(() => undefined);
|
|
26
28
|
const result = await contextOrient(path, options);
|
|
27
29
|
return {
|
|
28
30
|
content: [{ type: 'text', text: JSON.stringify(result) }],
|
|
@@ -3,7 +3,9 @@ export declare function learnKnowledge(startPath: string | undefined, statement:
|
|
|
3
3
|
export declare function listKnowledge(startPath?: string, includeUnverified?: boolean): Promise<Knowledge[]>;
|
|
4
4
|
export declare function discoverKnowledge(startPath: string | undefined, query: string, options?: KnowledgeDiscoverOptions): Promise<KnowledgeDiscoveryResult>;
|
|
5
5
|
export declare function verifyKnowledge(startPath: string | undefined, knowledgeId: string): Promise<Knowledge>;
|
|
6
|
+
export declare function transitionKnowledge(startPath: string | undefined, knowledgeId: string, status: 'deprecated' | 'rejected', reason: string): Promise<Knowledge>;
|
|
6
7
|
export declare function recordDeadend(startPath: string | undefined, attempt: string, reason: string, scopeOrInput?: string | DeadendInput): Promise<Deadend>;
|
|
7
8
|
export declare function listDeadends(startPath?: string, includeUnverified?: boolean): Promise<Deadend[]>;
|
|
8
9
|
export declare function discoverDeadends(startPath: string | undefined, query: string, options?: DeadendDiscoverOptions): Promise<DeadendDiscoveryResult>;
|
|
10
|
+
export declare function transitionDeadend(startPath: string | undefined, deadendId: string, status: 'obsolete' | 'rejected', reason: string): Promise<Deadend>;
|
|
9
11
|
export declare function verifyDeadend(startPath: string | undefined, deadendId: string): Promise<Deadend>;
|
|
@@ -35,6 +35,23 @@ function isKnowledgeFile(value) {
|
|
|
35
35
|
function cleanList(values) {
|
|
36
36
|
return [...new Set((values ?? []).map((value) => value.trim()).filter(Boolean))];
|
|
37
37
|
}
|
|
38
|
+
function cleanApplicability(input) {
|
|
39
|
+
if (!input)
|
|
40
|
+
return { project: true, branchMode: 'global' };
|
|
41
|
+
if (input.project !== true || !['global', 'exact'].includes(input.branchMode))
|
|
42
|
+
throw new Error('invalid record applicability');
|
|
43
|
+
const branches = cleanList(input.branches);
|
|
44
|
+
const paths = cleanList(input.paths);
|
|
45
|
+
if (input.branchMode === 'exact' && branches.length === 0)
|
|
46
|
+
throw new Error('exact applicability requires a branch');
|
|
47
|
+
return {
|
|
48
|
+
project: true,
|
|
49
|
+
branchMode: input.branchMode,
|
|
50
|
+
...(branches.length > 0 ? { branches } : {}),
|
|
51
|
+
...(paths.length > 0 ? { paths } : {}),
|
|
52
|
+
...(input.sourceCommit === undefined ? {} : { sourceCommit: input.sourceCommit }),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
38
55
|
function normalized(value) {
|
|
39
56
|
return value.trim().toLocaleLowerCase();
|
|
40
57
|
}
|
|
@@ -116,6 +133,7 @@ export async function learnKnowledge(startPath, statement, scopeOrInput = 'proje
|
|
|
116
133
|
sourceContextIds: cleanList(input.sourceContextId ? [input.sourceContextId] : []),
|
|
117
134
|
sourceSnapshotIds: cleanList(input.sourceSnapshotId ? [input.sourceSnapshotId] : []),
|
|
118
135
|
supportingEvidence: cleanList(input.evidence),
|
|
136
|
+
applicability: cleanApplicability(input.applicability),
|
|
119
137
|
createdAt: now,
|
|
120
138
|
updatedAt: now,
|
|
121
139
|
};
|
|
@@ -208,6 +226,8 @@ export async function verifyKnowledge(startPath, knowledgeId) {
|
|
|
208
226
|
const item = file.items.find((candidate) => candidate.knowledgeId === knowledgeId);
|
|
209
227
|
if (!item)
|
|
210
228
|
throw new Error(`knowledge not found: ${knowledgeId}`);
|
|
229
|
+
if (item.status !== 'candidate')
|
|
230
|
+
throw new Error(`knowledge must be a candidate to verify: ${knowledgeId}`);
|
|
211
231
|
item.status = 'verified';
|
|
212
232
|
item.confidence = Math.max(item.confidence, 0.8);
|
|
213
233
|
item.updatedAt = new Date().toISOString();
|
|
@@ -216,6 +236,26 @@ export async function verifyKnowledge(startPath, knowledgeId) {
|
|
|
216
236
|
return item;
|
|
217
237
|
});
|
|
218
238
|
}
|
|
239
|
+
export async function transitionKnowledge(startPath, knowledgeId, status, reason) {
|
|
240
|
+
const projectRoot = await resolveProjectRoot(startPath);
|
|
241
|
+
if (!reason.trim())
|
|
242
|
+
throw new Error('knowledge transition reason must not be empty');
|
|
243
|
+
return withLock(`${locksDirectory(projectRoot)}/knowledge.lock`, async () => {
|
|
244
|
+
const file = await loadKnowledge(projectRoot);
|
|
245
|
+
const item = file.items.find((candidate) => candidate.knowledgeId === knowledgeId);
|
|
246
|
+
if (!item)
|
|
247
|
+
throw new Error(`knowledge not found: ${knowledgeId}`);
|
|
248
|
+
if ((status === 'deprecated' && item.status !== 'verified') || (status === 'rejected' && item.status !== 'candidate')) {
|
|
249
|
+
throw new Error(`invalid knowledge transition: ${item.status} to ${status}`);
|
|
250
|
+
}
|
|
251
|
+
item.status = status;
|
|
252
|
+
item.updatedAt = new Date().toISOString();
|
|
253
|
+
item.governance = { reason: reason.trim(), transitionedAt: item.updatedAt };
|
|
254
|
+
await atomicWriteJson(knowledgePath(projectRoot), file);
|
|
255
|
+
await mirrorKnowledge(projectRoot, item);
|
|
256
|
+
return item;
|
|
257
|
+
});
|
|
258
|
+
}
|
|
219
259
|
export async function recordDeadend(startPath, attempt, reason, scopeOrInput = 'project') {
|
|
220
260
|
const projectRoot = await resolveProjectRoot(startPath);
|
|
221
261
|
const input = typeof scopeOrInput === 'string' ? { scope: scopeOrInput } : scopeOrInput;
|
|
@@ -232,6 +272,7 @@ export async function recordDeadend(startPath, attempt, reason, scopeOrInput = '
|
|
|
232
272
|
status: 'candidate',
|
|
233
273
|
sourceContextId: input.sourceContextId ?? null,
|
|
234
274
|
sourceSnapshotId: input.sourceSnapshotId ?? null,
|
|
275
|
+
applicability: cleanApplicability(input.applicability),
|
|
235
276
|
createdAt: now,
|
|
236
277
|
updatedAt: now,
|
|
237
278
|
};
|
|
@@ -288,6 +329,26 @@ export async function discoverDeadends(startPath, query, options = {}) {
|
|
|
288
329
|
hits: selected.map((item) => ({ ...item, deadend: limitedDeadend(item.deadend, maxChars) })),
|
|
289
330
|
};
|
|
290
331
|
}
|
|
332
|
+
export async function transitionDeadend(startPath, deadendId, status, reason) {
|
|
333
|
+
const projectRoot = await resolveProjectRoot(startPath);
|
|
334
|
+
if (!reason.trim())
|
|
335
|
+
throw new Error('deadend transition reason must not be empty');
|
|
336
|
+
return withLock(`${locksDirectory(projectRoot)}/deadends.lock`, async () => {
|
|
337
|
+
const file = await loadDeadends(projectRoot);
|
|
338
|
+
const item = file.items.find((candidate) => candidate.deadendId === deadendId);
|
|
339
|
+
if (!item)
|
|
340
|
+
throw new Error(`deadend not found: ${deadendId}`);
|
|
341
|
+
if ((status === 'obsolete' && item.status !== 'verified') || (status === 'rejected' && item.status !== 'candidate')) {
|
|
342
|
+
throw new Error(`invalid deadend transition: ${item.status} to ${status}`);
|
|
343
|
+
}
|
|
344
|
+
item.status = status;
|
|
345
|
+
item.updatedAt = new Date().toISOString();
|
|
346
|
+
item.governance = { reason: reason.trim(), transitionedAt: item.updatedAt };
|
|
347
|
+
await atomicWriteJson(deadendsPath(projectRoot), file);
|
|
348
|
+
await mirrorDeadend(projectRoot, item);
|
|
349
|
+
return item;
|
|
350
|
+
});
|
|
351
|
+
}
|
|
291
352
|
export async function verifyDeadend(startPath, deadendId) {
|
|
292
353
|
const projectRoot = await resolveProjectRoot(startPath);
|
|
293
354
|
return withLock(`${locksDirectory(projectRoot)}/deadends.lock`, async () => {
|
|
@@ -295,6 +356,8 @@ export async function verifyDeadend(startPath, deadendId) {
|
|
|
295
356
|
const item = file.items.find((candidate) => candidate.deadendId === deadendId);
|
|
296
357
|
if (!item)
|
|
297
358
|
throw new Error(`deadend not found: ${deadendId}`);
|
|
359
|
+
if (item.status !== 'candidate')
|
|
360
|
+
throw new Error(`deadend must be a candidate to verify: ${deadendId}`);
|
|
298
361
|
item.status = 'verified';
|
|
299
362
|
item.updatedAt = new Date().toISOString();
|
|
300
363
|
await atomicWriteJson(deadendsPath(projectRoot), file);
|
|
@@ -136,6 +136,13 @@ export interface ActivityResult {
|
|
|
136
136
|
}
|
|
137
137
|
export type KnowledgeStatus = 'candidate' | 'verified' | 'deprecated' | 'rejected';
|
|
138
138
|
export type DeadendStatus = 'candidate' | 'verified' | 'obsolete' | 'rejected';
|
|
139
|
+
export interface RecordApplicability {
|
|
140
|
+
project: true;
|
|
141
|
+
branches?: string[];
|
|
142
|
+
branchMode: 'global' | 'exact';
|
|
143
|
+
paths?: string[];
|
|
144
|
+
sourceCommit?: string | null;
|
|
145
|
+
}
|
|
139
146
|
export interface Knowledge {
|
|
140
147
|
knowledgeId: string;
|
|
141
148
|
kind: string;
|
|
@@ -146,6 +153,11 @@ export interface Knowledge {
|
|
|
146
153
|
sourceContextIds: string[];
|
|
147
154
|
sourceSnapshotIds: string[];
|
|
148
155
|
supportingEvidence: string[];
|
|
156
|
+
applicability?: RecordApplicability;
|
|
157
|
+
governance?: {
|
|
158
|
+
reason: string;
|
|
159
|
+
transitionedAt: string;
|
|
160
|
+
};
|
|
149
161
|
createdAt: string;
|
|
150
162
|
updatedAt: string;
|
|
151
163
|
}
|
|
@@ -155,6 +167,7 @@ export interface KnowledgeInput {
|
|
|
155
167
|
sourceContextId?: string;
|
|
156
168
|
sourceSnapshotId?: string;
|
|
157
169
|
evidence?: string[];
|
|
170
|
+
applicability?: RecordApplicability;
|
|
158
171
|
}
|
|
159
172
|
export interface KnowledgeDiscoverOptions {
|
|
160
173
|
scope?: string;
|
|
@@ -205,6 +218,7 @@ export interface DeadendInput {
|
|
|
205
218
|
sourceContextId?: string;
|
|
206
219
|
sourceSnapshotId?: string;
|
|
207
220
|
evidence?: string[];
|
|
221
|
+
applicability?: RecordApplicability;
|
|
208
222
|
}
|
|
209
223
|
export interface Deadend {
|
|
210
224
|
deadendId: string;
|
|
@@ -215,6 +229,11 @@ export interface Deadend {
|
|
|
215
229
|
status: DeadendStatus;
|
|
216
230
|
sourceContextId: string | null;
|
|
217
231
|
sourceSnapshotId: string | null;
|
|
232
|
+
applicability?: RecordApplicability;
|
|
233
|
+
governance?: {
|
|
234
|
+
reason: string;
|
|
235
|
+
transitionedAt: string;
|
|
236
|
+
};
|
|
218
237
|
createdAt: string;
|
|
219
238
|
updatedAt: string;
|
|
220
239
|
}
|
|
@@ -22,10 +22,12 @@ export declare function cognitionContextsProjectionPath(projectRoot: string): st
|
|
|
22
22
|
export declare function cognitionKnowledgeProjectionPath(projectRoot: string): string;
|
|
23
23
|
export declare function cognitionDeadendsProjectionPath(projectRoot: string): string;
|
|
24
24
|
export declare function cognitionNotesProjectionPath(projectRoot: string): string;
|
|
25
|
+
export declare function cognitionRetrievalProjectionPath(projectRoot: string): string;
|
|
25
26
|
export declare function cognitionMigrationsDirectory(projectRoot: string): string;
|
|
26
27
|
export declare function cognitionV1ImportPath(projectRoot: string): string;
|
|
27
28
|
export declare function cognitionRuntimeDirectory(projectRoot: string): string;
|
|
28
29
|
export declare function cognitionRuntimeLeasePath(projectRoot: string): string;
|
|
29
30
|
export declare function cognitionRuntimeSecretPath(projectRoot: string): string;
|
|
31
|
+
export declare function cognitionRuntimeStartupPath(projectRoot: string): string;
|
|
30
32
|
export declare function cognitionV1SyncPath(projectRoot: string): string;
|
|
31
33
|
export declare function cognitionQuarantineDirectory(projectRoot: string): string;
|
|
@@ -71,6 +71,9 @@ export function cognitionDeadendsProjectionPath(projectRoot) {
|
|
|
71
71
|
export function cognitionNotesProjectionPath(projectRoot) {
|
|
72
72
|
return path.join(cognitionProjectionsDirectory(projectRoot), 'notes.json');
|
|
73
73
|
}
|
|
74
|
+
export function cognitionRetrievalProjectionPath(projectRoot) {
|
|
75
|
+
return path.join(cognitionProjectionsDirectory(projectRoot), 'retrieval.json');
|
|
76
|
+
}
|
|
74
77
|
export function cognitionMigrationsDirectory(projectRoot) {
|
|
75
78
|
return path.join(cognitionRoot(projectRoot), 'migrations');
|
|
76
79
|
}
|
|
@@ -86,6 +89,9 @@ export function cognitionRuntimeLeasePath(projectRoot) {
|
|
|
86
89
|
export function cognitionRuntimeSecretPath(projectRoot) {
|
|
87
90
|
return path.join(cognitionRuntimeDirectory(projectRoot), 'secret');
|
|
88
91
|
}
|
|
92
|
+
export function cognitionRuntimeStartupPath(projectRoot) {
|
|
93
|
+
return path.join(cognitionRuntimeDirectory(projectRoot), 'startup.json');
|
|
94
|
+
}
|
|
89
95
|
export function cognitionV1SyncPath(projectRoot) {
|
|
90
96
|
return path.join(cognitionRuntimeDirectory(projectRoot), 'v1-sync.json');
|
|
91
97
|
}
|
package/dist/src/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
1
|
+
export declare const VERSION = "0.7.2";
|
package/dist/src/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '0.
|
|
1
|
+
export const VERSION = '0.7.2';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fluffy-context",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Local context management CLI and MCP tools for AI coding agents",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "FluffyChi-Xing",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"scripts": {
|
|
56
56
|
"build": "tsc -p tsconfig.json",
|
|
57
57
|
"typecheck": "tsc -p tsconfig.test.json --noEmit",
|
|
58
|
-
"test": "tsc -p tsconfig.test.json && node --test dist/test/*.test.js",
|
|
58
|
+
"test": "tsc -p tsconfig.test.json && node --test --test-concurrency=1 dist/test/*.test.js",
|
|
59
59
|
"pack:check": "tsc -p tsconfig.test.json && node --test dist/test/package-smoke.test.js",
|
|
60
60
|
"prepack": "npm run build",
|
|
61
61
|
"prepublishOnly": "npm test && npm run pack:check",
|
|
@@ -17,7 +17,8 @@ compatibility: 需要 Node.js >=20.19.0;Git 可选。CLI 通过 npm 全局安
|
|
|
17
17
|
- 人类需要了解 Agent 发生了什么时使用 `ctx activity`;它是只读时间线,不要求人类参与 Agent 的高频记录操作。
|
|
18
18
|
- 新会话与新任务优先运行 `ctx orient [query] --max-chars <预算>`;它只读地返回有界摘要、匹配的已验证共识和当前 Context 的 open Note,不会创建 Snapshot 或更新 `lastUsedAt`。
|
|
19
19
|
- 仅需要完整详情时再运行 `ctx resume --max-chars <预算>`;它会保留既有的 `lastUsedAt` 更新语义。
|
|
20
|
-
- Agent 集成从 `fluffy-context` 或 `fluffy-context/agent` 导入 `contextOrient`、`saveContext`、`loadContext` 和 `searchContext`,不应直接读写 `.context` 或导入内部 `dist/...` 路径。
|
|
20
|
+
- Agent 集成从 `fluffy-context` 或 `fluffy-context/agent` 导入 `contextOrient`、`compileContext`、`saveContext`、`loadContext` 和 `searchContext`,不应直接读写 `.context` 或导入内部 `dist/...` 路径。
|
|
21
|
+
- `ctx compile` 的 `activity` section 只表示 Runtime 观察到的近期文件 metadata 变化;它不代表文件被读取或理解,也不替代 checkpoint、Note 或已验证 Knowledge。
|
|
21
22
|
- 新任务先发现已验证共识,再开始实现;候选项只在显式审查时使用。
|
|
22
23
|
- 普通查询只使用已验证 Knowledge 和 Deadend;需要审查候选项时显式使用 `--all`。
|
|
23
24
|
- CLI 业务命令的标准输出是 JSON;错误写入标准错误并返回非零退出码。解析输出时不要把 `--help` 的纯文本当作 JSON。
|