brainclaw 0.19.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.
Files changed (128) hide show
  1. package/LICENSE +74 -0
  2. package/README.md +226 -0
  3. package/dist/cli.js +1037 -0
  4. package/dist/commands/accept.js +149 -0
  5. package/dist/commands/adapter-openclaw-import.js +75 -0
  6. package/dist/commands/add-step.js +35 -0
  7. package/dist/commands/agent-board.js +106 -0
  8. package/dist/commands/audit.js +35 -0
  9. package/dist/commands/bootstrap.js +34 -0
  10. package/dist/commands/capability.js +104 -0
  11. package/dist/commands/changes.js +112 -0
  12. package/dist/commands/check-constraints.js +63 -0
  13. package/dist/commands/claim-resource.js +54 -0
  14. package/dist/commands/claim.js +92 -0
  15. package/dist/commands/complete-step.js +34 -0
  16. package/dist/commands/constraint.js +44 -0
  17. package/dist/commands/context-diff.js +32 -0
  18. package/dist/commands/context.js +63 -0
  19. package/dist/commands/decision.js +45 -0
  20. package/dist/commands/delete-plan.js +20 -0
  21. package/dist/commands/diff.js +99 -0
  22. package/dist/commands/doctor.js +1275 -0
  23. package/dist/commands/enable-agent.js +63 -0
  24. package/dist/commands/env.js +46 -0
  25. package/dist/commands/estimation-report.js +167 -0
  26. package/dist/commands/explore.js +47 -0
  27. package/dist/commands/export.js +381 -0
  28. package/dist/commands/handoff.js +63 -0
  29. package/dist/commands/history.js +22 -0
  30. package/dist/commands/hooks.js +123 -0
  31. package/dist/commands/init.js +356 -0
  32. package/dist/commands/install-hooks.js +115 -0
  33. package/dist/commands/instruction.js +56 -0
  34. package/dist/commands/list-agents.js +44 -0
  35. package/dist/commands/list-claims.js +45 -0
  36. package/dist/commands/list-instructions.js +50 -0
  37. package/dist/commands/list-plans.js +48 -0
  38. package/dist/commands/mcp-worker.js +12 -0
  39. package/dist/commands/mcp.js +2272 -0
  40. package/dist/commands/memory.js +283 -0
  41. package/dist/commands/metrics.js +175 -0
  42. package/dist/commands/plan-resource.js +62 -0
  43. package/dist/commands/plan.js +76 -0
  44. package/dist/commands/prune-candidates.js +36 -0
  45. package/dist/commands/prune.js +48 -0
  46. package/dist/commands/pull.js +25 -0
  47. package/dist/commands/push.js +28 -0
  48. package/dist/commands/rebuild.js +14 -0
  49. package/dist/commands/reflect-runtime-note.js +74 -0
  50. package/dist/commands/reflect.js +286 -0
  51. package/dist/commands/register-agent.js +29 -0
  52. package/dist/commands/reject.js +52 -0
  53. package/dist/commands/release-claim.js +41 -0
  54. package/dist/commands/release-claims.js +67 -0
  55. package/dist/commands/review.js +242 -0
  56. package/dist/commands/rollback.js +156 -0
  57. package/dist/commands/runtime-note.js +144 -0
  58. package/dist/commands/runtime-status.js +49 -0
  59. package/dist/commands/search.js +36 -0
  60. package/dist/commands/session-end.js +187 -0
  61. package/dist/commands/session-start.js +147 -0
  62. package/dist/commands/set-trust.js +92 -0
  63. package/dist/commands/setup.js +446 -0
  64. package/dist/commands/show-candidate.js +31 -0
  65. package/dist/commands/star-candidate.js +28 -0
  66. package/dist/commands/status.js +133 -0
  67. package/dist/commands/sync.js +159 -0
  68. package/dist/commands/tool.js +126 -0
  69. package/dist/commands/trap.js +74 -0
  70. package/dist/commands/update-handoff.js +23 -0
  71. package/dist/commands/update-plan.js +37 -0
  72. package/dist/commands/upgrade.js +382 -0
  73. package/dist/commands/use-candidate.js +35 -0
  74. package/dist/commands/version.js +96 -0
  75. package/dist/commands/watch.js +215 -0
  76. package/dist/commands/whoami.js +104 -0
  77. package/dist/core/agent-context.js +340 -0
  78. package/dist/core/agent-files.js +874 -0
  79. package/dist/core/agent-integrations.js +135 -0
  80. package/dist/core/agent-inventory.js +401 -0
  81. package/dist/core/agent-registry.js +420 -0
  82. package/dist/core/ai-agent-detection.js +140 -0
  83. package/dist/core/audit.js +85 -0
  84. package/dist/core/bootstrap.js +658 -0
  85. package/dist/core/brainclaw-version.js +433 -0
  86. package/dist/core/candidates.js +137 -0
  87. package/dist/core/circuit-breaker.js +118 -0
  88. package/dist/core/claims.js +72 -0
  89. package/dist/core/config.js +86 -0
  90. package/dist/core/context-diff.js +122 -0
  91. package/dist/core/context.js +1212 -0
  92. package/dist/core/contradictions.js +270 -0
  93. package/dist/core/coordination.js +86 -0
  94. package/dist/core/cross-project.js +99 -0
  95. package/dist/core/duplicates.js +72 -0
  96. package/dist/core/event-log.js +152 -0
  97. package/dist/core/events.js +56 -0
  98. package/dist/core/execution-context.js +204 -0
  99. package/dist/core/freshness.js +87 -0
  100. package/dist/core/global-registry.js +182 -0
  101. package/dist/core/host.js +10 -0
  102. package/dist/core/identity.js +151 -0
  103. package/dist/core/ids.js +56 -0
  104. package/dist/core/input-validation.js +81 -0
  105. package/dist/core/instructions.js +117 -0
  106. package/dist/core/io.js +191 -0
  107. package/dist/core/json-store.js +63 -0
  108. package/dist/core/lifecycle.js +45 -0
  109. package/dist/core/lock.js +129 -0
  110. package/dist/core/logger.js +49 -0
  111. package/dist/core/machine-profile.js +332 -0
  112. package/dist/core/markdown.js +120 -0
  113. package/dist/core/memory-git.js +133 -0
  114. package/dist/core/migration.js +247 -0
  115. package/dist/core/project-registry.js +64 -0
  116. package/dist/core/reflection-safety.js +21 -0
  117. package/dist/core/repo-analysis.js +133 -0
  118. package/dist/core/reputation.js +409 -0
  119. package/dist/core/runtime.js +134 -0
  120. package/dist/core/schema.js +580 -0
  121. package/dist/core/search.js +115 -0
  122. package/dist/core/security.js +66 -0
  123. package/dist/core/setup-state.js +50 -0
  124. package/dist/core/state.js +83 -0
  125. package/dist/core/store-resolution.js +119 -0
  126. package/dist/core/sync-remote.js +83 -0
  127. package/dist/core/traps.js +86 -0
  128. package/package.json +60 -0
@@ -0,0 +1,63 @@
1
+ import { execSync } from 'node:child_process';
2
+ import { loadState } from '../core/state.js';
3
+ import { memoryExists } from '../core/io.js';
4
+ /** Normalise a path to forward slashes and strip leading ./ */
5
+ function normPath(p) {
6
+ return p.replace(/\\/g, '/').replace(/^\.\//, '');
7
+ }
8
+ /** Returns true if any staged file matches a related_path (prefix or exact). */
9
+ function pathMatches(stagedFile, relatedPath) {
10
+ const f = normPath(stagedFile);
11
+ const r = normPath(relatedPath).replace(/\/$/, '');
12
+ return f === r || f.startsWith(r + '/');
13
+ }
14
+ export function runCheckConstraints(options = {}) {
15
+ if (!memoryExists()) {
16
+ // Silent exit — hook context, not interactive
17
+ process.exit(0);
18
+ }
19
+ let filesToCheck = options.files ?? [];
20
+ if (options.staged) {
21
+ try {
22
+ const output = execSync('git diff --cached --name-only', { encoding: 'utf-8' });
23
+ filesToCheck = output.split('\n').map((f) => f.trim()).filter(Boolean);
24
+ }
25
+ catch {
26
+ // Not in a git repo or no staged files — silent pass
27
+ process.exit(0);
28
+ }
29
+ }
30
+ if (filesToCheck.length === 0) {
31
+ process.exit(0);
32
+ }
33
+ const state = loadState();
34
+ const violations = [];
35
+ for (const constraint of state.active_constraints) {
36
+ if (!constraint.related_paths || constraint.related_paths.length === 0)
37
+ continue;
38
+ const matched = filesToCheck.filter((f) => constraint.related_paths.some((rp) => pathMatches(f, rp)));
39
+ if (matched.length > 0) {
40
+ violations.push({
41
+ constraintId: constraint.id,
42
+ constraintText: constraint.text,
43
+ matchedFiles: matched,
44
+ });
45
+ }
46
+ }
47
+ if (options.json) {
48
+ console.log(JSON.stringify({ violations, staged_files: filesToCheck }, null, 2));
49
+ process.exit(violations.length > 0 ? 1 : 0);
50
+ }
51
+ if (violations.length === 0) {
52
+ process.exit(0);
53
+ }
54
+ process.stderr.write('\nbrainclaw: active constraint(s) cover staged files — commit blocked.\n\n');
55
+ for (const v of violations) {
56
+ process.stderr.write(` ⚠ [${v.constraintId}] ${v.constraintText}\n`);
57
+ process.stderr.write(` Files: ${v.matchedFiles.join(', ')}\n\n`);
58
+ }
59
+ process.stderr.write(' Review constraints: brainclaw status\n');
60
+ process.stderr.write(' To bypass (not recommended): git commit --no-verify\n\n');
61
+ process.exit(1);
62
+ }
63
+ //# sourceMappingURL=check-constraints.js.map
@@ -0,0 +1,54 @@
1
+ import { runClaim } from './claim.js';
2
+ import { runListClaims } from './list-claims.js';
3
+ import { runReleaseClaim } from './release-claim.js';
4
+ export function runClaimResource(subcommand, args, options) {
5
+ const normalized = subcommand.trim().toLowerCase();
6
+ if (normalized === 'create') {
7
+ const description = args.join(' ').trim();
8
+ if (!description) {
9
+ console.error('Error: claim create requires <description>');
10
+ process.exit(1);
11
+ }
12
+ if (!options.scope) {
13
+ console.error('Error: claim create requires --scope <scope>');
14
+ process.exit(1);
15
+ }
16
+ runClaim(description, options);
17
+ return;
18
+ }
19
+ if (normalized === 'list' || normalized === 'ls') {
20
+ runListClaims({
21
+ json: options.json,
22
+ all: options.all,
23
+ project: options.project,
24
+ plan: options.plan,
25
+ agent: options.agent,
26
+ cwd: options.cwd,
27
+ });
28
+ return;
29
+ }
30
+ if (normalized === 'release') {
31
+ const id = args[0];
32
+ if (!id) {
33
+ console.error('Error: claim release requires <id>');
34
+ process.exit(1);
35
+ }
36
+ runReleaseClaim(id, {
37
+ planStatus: options.planStatus,
38
+ cwd: options.cwd,
39
+ });
40
+ return;
41
+ }
42
+ // Compatibility path: `brainclaw claim "description" --scope ...`
43
+ const legacyDescription = [subcommand, ...args].join(' ').trim();
44
+ if (!legacyDescription) {
45
+ console.error('Error: missing claim subcommand or description.');
46
+ process.exit(1);
47
+ }
48
+ if (!options.scope) {
49
+ console.error('Error: claim create requires --scope <scope>');
50
+ process.exit(1);
51
+ }
52
+ runClaim(legacyDescription, options);
53
+ }
54
+ //# sourceMappingURL=claim-resource.js.map
@@ -0,0 +1,92 @@
1
+ import { buildOperationalIdentity } from '../core/identity.js';
2
+ import { memoryExists, memoryPath, writeFileAtomic } from '../core/io.js';
3
+ import { saveClaim, generateClaimId, listClaims } from '../core/claims.js';
4
+ import { generateMarkdown } from '../core/markdown.js';
5
+ import { loadState, saveState } from '../core/state.js';
6
+ import { nowISO } from '../core/ids.js';
7
+ import { requireMinimumTrustLevel, requireRegisteredAgentIdentity } from '../core/agent-registry.js';
8
+ import { validateCliTtl } from '../core/input-validation.js';
9
+ import { resolveTargetStore } from '../core/store-resolution.js';
10
+ function parseTtl(ttl) {
11
+ const match = /^(\d+)([mhd])$/.exec(ttl.trim().toLowerCase());
12
+ if (!match)
13
+ return new Date(Date.now() + 8 * 3_600_000).toISOString();
14
+ const value = parseInt(match[1], 10);
15
+ const unit = match[2];
16
+ const ms = unit === 'm' ? value * 60_000 : unit === 'h' ? value * 3_600_000 : value * 86_400_000;
17
+ return new Date(Date.now() + ms).toISOString();
18
+ }
19
+ export function runClaim(description, options) {
20
+ const cwd = resolveTargetStore(options.cwd ?? process.cwd(), options.store ?? 'local');
21
+ options = { ...options, cwd };
22
+ if (!memoryExists(options.cwd)) {
23
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
24
+ process.exit(1);
25
+ }
26
+ if (options.ttl)
27
+ validateCliTtl(options.ttl);
28
+ let actor;
29
+ try {
30
+ const registered = requireRegisteredAgentIdentity({
31
+ agentName: options.agent,
32
+ agentId: options.agentId,
33
+ cwd: options.cwd,
34
+ allowCurrent: true,
35
+ allowEnv: true,
36
+ });
37
+ requireMinimumTrustLevel(registered, 'contributor');
38
+ actor = buildOperationalIdentity(registered.agent_name, options.cwd, { agentId: registered.agent_id });
39
+ }
40
+ catch (error) {
41
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
42
+ process.exit(1);
43
+ }
44
+ // Check for overlapping active claims on the same scope
45
+ const existing = listClaims(options.cwd).filter(c => c.status === 'active' && c.scope === options.scope);
46
+ if (existing.length > 0) {
47
+ console.warn(`⚠ Active claim(s) already exist for scope "${options.scope}":`);
48
+ for (const c of existing) {
49
+ console.warn(` [${c.id}] by ${c.agent}: ${c.description}`);
50
+ }
51
+ console.warn(' Proceeding anyway (advisory only).');
52
+ }
53
+ const state = loadState(options.cwd);
54
+ const plan = options.plan ? state.plan_items.find((item) => item.id === options.plan) : undefined;
55
+ if (options.plan && !plan) {
56
+ console.error(`Error: Plan item '${options.plan}' not found.`);
57
+ process.exit(1);
58
+ }
59
+ const id = generateClaimId();
60
+ const claim = {
61
+ id,
62
+ agent: actor.agent,
63
+ agent_id: actor.agent_id,
64
+ project_id: actor.project_id,
65
+ host_id: actor.host_id,
66
+ session_id: actor.session_id,
67
+ scope: options.scope,
68
+ description,
69
+ created_at: nowISO(),
70
+ project: options.project ?? plan?.project,
71
+ plan_id: options.plan,
72
+ status: 'active',
73
+ expires_at: options.ttl ? parseTtl(options.ttl) : undefined,
74
+ };
75
+ if (plan) {
76
+ if (!plan.assignee) {
77
+ plan.assignee = actor.agent;
78
+ }
79
+ if (plan.status === 'todo') {
80
+ plan.status = 'in_progress';
81
+ }
82
+ plan.updated_at = nowISO();
83
+ saveState(state, options.cwd);
84
+ }
85
+ saveClaim(claim, options.cwd);
86
+ writeFileAtomic(memoryPath('project.md', options.cwd), generateMarkdown(plan ? state : loadState(options.cwd), options.cwd));
87
+ const planInfo = claim.plan_id ? ` [plan ${claim.plan_id}]` : '';
88
+ const ttlInfo = claim.expires_at ? ` (expires ${claim.expires_at.slice(0, 16).replace('T', ' ')})` : '';
89
+ const storeLabel = options.store && options.store !== 'local' ? ` [store:${options.store}]` : '';
90
+ console.log(`✔ Claim created: [${id}] ${actor.agent} → ${options.scope}: ${description}${planInfo}${ttlInfo}${storeLabel}`);
91
+ }
92
+ //# sourceMappingURL=claim.js.map
@@ -0,0 +1,34 @@
1
+ import { loadState, saveState } from '../core/state.js';
2
+ import { memoryExists, memoryPath, writeFileAtomic } from '../core/io.js';
3
+ import { nowISO } from '../core/ids.js';
4
+ import { generateMarkdown } from '../core/markdown.js';
5
+ export function runCompleteStep(planId, stepId) {
6
+ if (!memoryExists()) {
7
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
8
+ process.exit(1);
9
+ }
10
+ const state = loadState();
11
+ const plan = state.plan_items.find((p) => p.id === planId || p.short_label === planId);
12
+ if (!plan) {
13
+ console.error(`Error: Plan '${planId}' not found.`);
14
+ process.exit(1);
15
+ }
16
+ const step = (plan.steps ?? []).find((s) => s.id === stepId);
17
+ if (!step) {
18
+ console.error(`Error: Step '${stepId}' not found in plan '${planId}'.`);
19
+ process.exit(1);
20
+ }
21
+ step.status = 'done';
22
+ step.updated_at = nowISO();
23
+ plan.updated_at = nowISO();
24
+ saveState(state);
25
+ writeFileAtomic(memoryPath('project.md'), generateMarkdown(state));
26
+ const total = plan.steps.length;
27
+ const done = plan.steps.filter((s) => s.status === 'done').length;
28
+ console.log(`✔ Step completed: [${step.id}] ${step.text}`);
29
+ console.log(` Plan [${plan.id}] progress: ${done}/${total} steps done`);
30
+ if (done === total) {
31
+ console.log(` All steps done — consider: brainclaw update-plan ${plan.id} --status done`);
32
+ }
33
+ }
34
+ //# sourceMappingURL=complete-step.js.map
@@ -0,0 +1,44 @@
1
+ import { loadState, saveState } from '../core/state.js';
2
+ import { resolveCurrentAgentName } from '../core/agent-registry.js';
3
+ import { loadConfig } from '../core/config.js';
4
+ import { generateMarkdown } from '../core/markdown.js';
5
+ import { generateIdWithLabel, nowISO } from '../core/ids.js';
6
+ import { scanText } from '../core/security.js';
7
+ import { memoryExists, memoryPath, writeFileAtomic } from '../core/io.js';
8
+ import { validateCliInput } from '../core/input-validation.js';
9
+ import { resolveTargetStore } from '../core/store-resolution.js';
10
+ export function runConstraint(text, options = {}) {
11
+ const cwd = resolveTargetStore(options.cwd ?? process.cwd(), options.store ?? 'local');
12
+ if (!memoryExists(cwd)) {
13
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
14
+ process.exit(1);
15
+ }
16
+ validateCliInput(text, options.tag);
17
+ const config = loadConfig(cwd);
18
+ const warnings = scanText(text, config);
19
+ for (const w of warnings) {
20
+ console.warn(`⚠ ${w.message}`);
21
+ if (w.level === 'block') {
22
+ console.error('Blocked: strict redaction is enabled. Entry not added.');
23
+ process.exit(1);
24
+ }
25
+ }
26
+ const state = loadState(cwd);
27
+ const { id, short_label } = generateIdWithLabel('active_constraints');
28
+ const entry = {
29
+ id,
30
+ short_label,
31
+ text,
32
+ created_at: nowISO(),
33
+ author: options.author ?? resolveCurrentAgentName(cwd),
34
+ status: 'active',
35
+ category: options.category,
36
+ tags: options.tag ?? [],
37
+ related_paths: options.path,
38
+ };
39
+ state.active_constraints.push(entry);
40
+ saveState(state, cwd);
41
+ writeFileAtomic(memoryPath('project.md', cwd), generateMarkdown(state));
42
+ console.log(`✔ Constraint added: [${id}] ${text}`);
43
+ }
44
+ //# sourceMappingURL=constraint.js.map
@@ -0,0 +1,32 @@
1
+ import { buildContextDiff, resolveContextDiffSince } from '../core/context-diff.js';
2
+ import { memoryExists } from '../core/io.js';
3
+ export function runContextDiff(options = {}) {
4
+ if (!memoryExists(options.cwd)) {
5
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
6
+ process.exit(1);
7
+ }
8
+ const resolved = resolveContextDiffSince(options);
9
+ if (!resolved.since) {
10
+ if (options.session) {
11
+ console.error(`Error: session '${options.session}' not found in session snapshots or audit log.`);
12
+ process.exit(1);
13
+ }
14
+ console.error('Error: provide --since <ISO date> or --session <id>, or run `brainclaw context` first to seed a marker.');
15
+ process.exit(1);
16
+ }
17
+ const diff = buildContextDiff({ ...options, includeItems: true });
18
+ if (!diff) {
19
+ console.error('Error: unable to build context diff.');
20
+ process.exit(1);
21
+ }
22
+ if (options.json) {
23
+ console.log(JSON.stringify(diff, null, 2));
24
+ return;
25
+ }
26
+ if (diff.counts.total === 0) {
27
+ console.log(`${diff.summary} since ${diff.since}.`);
28
+ return;
29
+ }
30
+ console.log(`${diff.summary} since ${diff.since}.`);
31
+ }
32
+ //# sourceMappingURL=context-diff.js.map
@@ -0,0 +1,63 @@
1
+ import { memoryExists } from '../core/io.js';
2
+ import { buildContext, renderContextMarkdown, renderContextPromptTemplate } from '../core/context.js';
3
+ import { writeContextMarker } from '../core/freshness.js';
4
+ import { nowISO } from '../core/ids.js';
5
+ import { logger } from '../core/logger.js';
6
+ export function runContext(options = {}) {
7
+ const cwd = options.cwd ?? process.cwd();
8
+ if (!memoryExists(cwd)) {
9
+ if (options.json) {
10
+ console.log(JSON.stringify({
11
+ initialized: false,
12
+ action_required: 'Run `brainclaw init` to initialize project memory.',
13
+ }, null, 2));
14
+ }
15
+ else {
16
+ console.log('brainclaw: project memory not initialized. Run `brainclaw init` first.');
17
+ }
18
+ return;
19
+ }
20
+ const result = buildContext({
21
+ target: options.for,
22
+ project: options.project,
23
+ agent: options.agent,
24
+ host: options.host,
25
+ allHosts: options.allHosts,
26
+ includePending: options.includePending,
27
+ profile: options.profile,
28
+ maxItems: options.maxItems,
29
+ maxChars: options.maxChars,
30
+ digest: options.digest,
31
+ bootstrap: options.bootstrap,
32
+ refreshBootstrap: options.refreshBootstrap,
33
+ sinceSession: options.sinceSession,
34
+ cwd,
35
+ });
36
+ if (options.json) {
37
+ console.log(JSON.stringify(result, null, 2));
38
+ }
39
+ else if (options.template) {
40
+ const compact = options.compactTemplate || result.profile === 'openclaw';
41
+ console.log(renderContextPromptTemplate(result, compact));
42
+ }
43
+ else {
44
+ console.log(renderContextMarkdown(result, options.explain));
45
+ }
46
+ writeLastContextMarker(result, options, cwd);
47
+ }
48
+ function writeLastContextMarker(result, options, cwd) {
49
+ try {
50
+ writeContextMarker({
51
+ read_at: nowISO(),
52
+ memory_version: result.memory_version,
53
+ host_id: result.current_host,
54
+ target: options.for,
55
+ project: result.project,
56
+ all_hosts: options.allHosts ?? false,
57
+ }, cwd);
58
+ }
59
+ catch (err) {
60
+ logger.debug('Failed to write context marker:', err);
61
+ }
62
+ }
63
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1,45 @@
1
+ import { loadState, saveState } from '../core/state.js';
2
+ import { resolveCurrentAgentName } from '../core/agent-registry.js';
3
+ import { loadConfig } from '../core/config.js';
4
+ import { generateMarkdown } from '../core/markdown.js';
5
+ import { generateIdWithLabel, nowISO } from '../core/ids.js';
6
+ import { scanText } from '../core/security.js';
7
+ import { memoryExists, memoryPath, writeFileAtomic } from '../core/io.js';
8
+ import { validateCliInput } from '../core/input-validation.js';
9
+ import { resolveTargetStore } from '../core/store-resolution.js';
10
+ export function runDecision(text, options = {}) {
11
+ const cwd = resolveTargetStore(options.cwd ?? process.cwd(), options.store ?? 'local');
12
+ if (!memoryExists(cwd)) {
13
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
14
+ process.exit(1);
15
+ }
16
+ validateCliInput(text, options.tag);
17
+ const config = loadConfig(cwd);
18
+ const warnings = scanText(text, config);
19
+ for (const w of warnings) {
20
+ console.warn(`⚠ ${w.message}`);
21
+ if (w.level === 'block') {
22
+ console.error('Blocked: strict redaction is enabled. Entry not added.');
23
+ process.exit(1);
24
+ }
25
+ }
26
+ const state = loadState(cwd);
27
+ const { id, short_label } = generateIdWithLabel('recent_decisions');
28
+ const entry = {
29
+ id,
30
+ short_label,
31
+ text,
32
+ created_at: nowISO(),
33
+ author: options.author ?? resolveCurrentAgentName(cwd),
34
+ outcome: options.outcome,
35
+ tags: options.tag ?? [],
36
+ related_paths: options.path,
37
+ plan_id: options.plan,
38
+ };
39
+ state.recent_decisions.push(entry);
40
+ saveState(state, cwd);
41
+ // Rebuild markdown
42
+ writeFileAtomic(memoryPath('project.md', cwd), generateMarkdown(state));
43
+ console.log(`✔ Decision added: [${id}] ${text}`);
44
+ }
45
+ //# sourceMappingURL=decision.js.map
@@ -0,0 +1,20 @@
1
+ import { loadState, saveState } from '../core/state.js';
2
+ import { memoryExists, memoryPath, writeFileAtomic } from '../core/io.js';
3
+ import { generateMarkdown } from '../core/markdown.js';
4
+ export function runDeletePlan(id, options = {}) {
5
+ if (!memoryExists(options.cwd)) {
6
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
7
+ process.exit(1);
8
+ }
9
+ const state = loadState(options.cwd);
10
+ const index = state.plan_items.findIndex((item) => item.id === id || item.short_label === id);
11
+ if (index < 0) {
12
+ console.error(`Error: Plan item '${id}' not found.`);
13
+ process.exit(1);
14
+ }
15
+ const [plan] = state.plan_items.splice(index, 1);
16
+ saveState(state, options.cwd);
17
+ writeFileAtomic(memoryPath('project.md', options.cwd), generateMarkdown(state, options.cwd));
18
+ console.log(`✔ Plan item deleted: [${plan.id}] ${plan.text}`);
19
+ }
20
+ //# sourceMappingURL=delete-plan.js.map
@@ -0,0 +1,99 @@
1
+ import { memoryExists, memoryPath, readFileSync, writeFileAtomic } from '../core/io.js';
2
+ import { loadState } from '../core/state.js';
3
+ import { listCandidates, listArchivedCandidates } from '../core/candidates.js';
4
+ import { nowISO } from '../core/ids.js';
5
+ export function runDiff(options = {}) {
6
+ if (!memoryExists()) {
7
+ console.error('Error: .memory/ not found. Run `team-memory init` first.');
8
+ process.exit(1);
9
+ }
10
+ const markerPath = memoryPath('.last-context');
11
+ const usingMarker = !options.since;
12
+ let since;
13
+ if (options.since) {
14
+ since = new Date(options.since);
15
+ if (isNaN(since.getTime())) {
16
+ console.error(`Error: invalid date '${options.since}'. Use ISO 8601 format, e.g. 2026-03-14T10:00:00Z`);
17
+ process.exit(1);
18
+ }
19
+ }
20
+ else {
21
+ try {
22
+ const ts = readFileSync(markerPath).trim();
23
+ since = new Date(ts);
24
+ if (isNaN(since.getTime()))
25
+ throw new Error('invalid date in .last-context');
26
+ }
27
+ catch {
28
+ console.error('Error: no --since date provided and no .last-context marker found.');
29
+ console.error('Hint: run `team-memory context` first to set the marker, or use:');
30
+ console.error(' team-memory diff --since <ISO date>');
31
+ process.exit(1);
32
+ }
33
+ }
34
+ const sinceISO = since.toISOString();
35
+ const state = loadState();
36
+ const makeEntry = (section, type) => (e) => ({
37
+ id: e.id, entry_type: type, section, text: e.text, created_at: e.created_at,
38
+ });
39
+ const stateEntries = [
40
+ ...state.active_constraints.filter(e => e.created_at > sinceISO).map(makeEntry('active_constraints', 'constraint')),
41
+ ...state.recent_decisions.filter(e => e.created_at > sinceISO).map(makeEntry('recent_decisions', 'decision')),
42
+ ...state.known_traps.filter(e => e.created_at > sinceISO).map(makeEntry('known_traps', 'trap')),
43
+ ...state.open_handoffs.filter(e => e.created_at > sinceISO).map(makeEntry('open_handoffs', 'handoff')),
44
+ ].sort((a, b) => a.created_at.localeCompare(b.created_at));
45
+ const newPending = listCandidates('pending').filter(c => c.created_at > sinceISO);
46
+ const newAccepted = listArchivedCandidates('accepted').filter(c => (c.resolved_at ?? c.created_at) > sinceISO);
47
+ const total = stateEntries.length + newPending.length + newAccepted.length;
48
+ if (options.json) {
49
+ console.log(JSON.stringify({
50
+ since: sinceISO,
51
+ checked_at: new Date().toISOString(),
52
+ total_changes: total,
53
+ state_entries: stateEntries,
54
+ new_candidates: newPending,
55
+ accepted_candidates: newAccepted,
56
+ }, null, 2));
57
+ }
58
+ else {
59
+ if (total === 0) {
60
+ console.log(`No changes in .memory/ since ${sinceISO}`);
61
+ }
62
+ else {
63
+ console.log(`Changes since ${sinceISO}:`);
64
+ console.log('');
65
+ if (stateEntries.length > 0) {
66
+ console.log(`New canonical entries (${stateEntries.length}):`);
67
+ for (const e of stateEntries) {
68
+ console.log(` + [${e.id}] (${e.entry_type}) ${e.text}`);
69
+ }
70
+ }
71
+ if (newPending.length > 0) {
72
+ if (stateEntries.length > 0)
73
+ console.log('');
74
+ console.log(`New candidates pending review (${newPending.length}):`);
75
+ for (const c of newPending) {
76
+ console.log(` ? [${c.id}] (${c.type}) ${c.text}`);
77
+ }
78
+ }
79
+ if (newAccepted.length > 0) {
80
+ console.log('');
81
+ console.log(`Candidates accepted into memory (${newAccepted.length}):`);
82
+ for (const c of newAccepted) {
83
+ console.log(` \u2714 [${c.id}] (${c.type}) ${c.text}`);
84
+ }
85
+ }
86
+ }
87
+ }
88
+ // When called without explicit --since, advance the marker so the next
89
+ // diff (no --since) starts from here — acts as a cursor.
90
+ if (usingMarker) {
91
+ try {
92
+ writeFileAtomic(markerPath, nowISO());
93
+ }
94
+ catch {
95
+ // Non-fatal
96
+ }
97
+ }
98
+ }
99
+ //# sourceMappingURL=diff.js.map