moflo 4.12.4 → 4.12.6

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 (110) hide show
  1. package/.claude/guidance/shipped/moflo-agent-rules.md +1 -0
  2. package/.claude/guidance/shipped/moflo-claude-swarm-cohesion.md +1 -1
  3. package/.claude/guidance/shipped/moflo-cli-reference.md +4 -4
  4. package/.claude/guidance/shipped/moflo-core-guidance.md +4 -4
  5. package/.claude/guidance/shipped/moflo-guidance-rules.md +21 -0
  6. package/.claude/guidance/shipped/moflo-inline-fixes.md +98 -0
  7. package/.claude/guidance/shipped/moflo-root-cause-discipline.md +10 -10
  8. package/.claude/guidance/shipped/moflo-sdd.md +5 -5
  9. package/.claude/guidance/shipped/moflo-spell-engine.md +1 -1
  10. package/.claude/guidance/shipped/moflo-yaml-reference.md +8 -8
  11. package/.claude/helpers/gate.cjs +46 -7
  12. package/.claude/helpers/pr-create-command.cjs +440 -0
  13. package/.claude/skills/eldar/SKILL.md +1 -1
  14. package/.claude/skills/fl/SKILL.md +6 -6
  15. package/.claude/skills/fl/execution-modes.md +3 -3
  16. package/.claude/skills/fl/phases.md +8 -8
  17. package/.claude/skills/fl/sdd.md +6 -6
  18. package/.claude/skills/guidance/SKILL.md +3 -0
  19. package/.claude/skills/verify/SKILL.md +4 -4
  20. package/bin/gate.cjs +46 -7
  21. package/bin/hooks.mjs +4 -1
  22. package/bin/lib/retired-files.mjs +38 -6
  23. package/bin/lib/shipped-scripts.json +2 -1
  24. package/bin/lib/skill-categories.mjs +81 -17
  25. package/bin/pr-create-command.cjs +440 -0
  26. package/bin/session-start-launcher.mjs +11 -6
  27. package/dist/src/cli/aidefence/domain/entities/threat.js +2 -1
  28. package/dist/src/cli/commands/doctor-checks-deep.js +3 -2
  29. package/dist/src/cli/commands/doctor-checks-memory-access.js +3 -2
  30. package/dist/src/cli/commands/doctor-checks-swarm.js +3 -2
  31. package/dist/src/cli/commands/doctor-fixes.js +119 -20
  32. package/dist/src/cli/commands/hooks.js +2 -1
  33. package/dist/src/cli/commands/mcp.js +3 -2
  34. package/dist/src/cli/commands/memory.js +2 -1
  35. package/dist/src/cli/commands/performance.js +2 -1
  36. package/dist/src/cli/commands/retire.js +1 -1
  37. package/dist/src/cli/commands/spell-schedule.js +2 -1
  38. package/dist/src/cli/commands/swarm.js +216 -104
  39. package/dist/src/cli/guidance/headless.js +5 -8
  40. package/dist/src/cli/guidance/retriever.js +27 -6
  41. package/dist/src/cli/guidance/ruvbot-integration.js +2 -1
  42. package/dist/src/cli/guidance/uncertainty.js +2 -1
  43. package/dist/src/cli/hooks/bridge/official-hooks-bridge.js +2 -1
  44. package/dist/src/cli/hooks/mcp/index.js +3 -2
  45. package/dist/src/cli/hooks/reasoningbank/index.js +2 -1
  46. package/dist/src/cli/hooks/registry/index.js +2 -1
  47. package/dist/src/cli/hooks/swarm/index.js +6 -5
  48. package/dist/src/cli/init/claudemd-generator.js +2 -1
  49. package/dist/src/cli/init/helpers-generator.js +1 -1
  50. package/dist/src/cli/init/moflo-yaml-template.js +4 -4
  51. package/dist/src/cli/mcp-client.js +5 -2
  52. package/dist/src/cli/mcp-tools/agent-tools.js +4 -1
  53. package/dist/src/cli/mcp-tools/hive-mind-tools.js +4 -3
  54. package/dist/src/cli/mcp-tools/hooks-tools.js +6 -5
  55. package/dist/src/cli/mcp-tools/json-store.js +3 -2
  56. package/dist/src/cli/mcp-tools/neural-tools.js +2 -1
  57. package/dist/src/cli/mcp-tools/performance-tools.js +2 -1
  58. package/dist/src/cli/mcp-tools/session-tools.js +4 -2
  59. package/dist/src/cli/mcp-tools/spell-tools.js +2 -1
  60. package/dist/src/cli/memory/bridge-core.js +8 -2
  61. package/dist/src/cli/memory/controllers/_shared.js +8 -2
  62. package/dist/src/cli/memory/controllers/nightly-learner.js +2 -1
  63. package/dist/src/cli/memory/domain/services/memory-domain-service.js +2 -1
  64. package/dist/src/cli/memory/entries-write.js +2 -1
  65. package/dist/src/cli/memory/intelligence.js +2 -1
  66. package/dist/src/cli/memory/persistent-sona.js +1 -3
  67. package/dist/src/cli/memory/types.js +2 -3
  68. package/dist/src/cli/memory/verify.js +3 -2
  69. package/dist/src/cli/movector/graph-analyzer.js +14 -3
  70. package/dist/src/cli/neural/pattern-learner.js +4 -2
  71. package/dist/src/cli/neural/reasoning-bank.js +2 -1
  72. package/dist/src/cli/neural/reasoningbank-adapter.js +2 -1
  73. package/dist/src/cli/neural/sona-manager.js +4 -3
  74. package/dist/src/cli/production/monitoring.js +2 -1
  75. package/dist/src/cli/services/daemon-service.js +57 -46
  76. package/dist/src/cli/services/daemon-spell-executor.js +3 -2
  77. package/dist/src/cli/services/headless-worker-executor.js +4 -2
  78. package/dist/src/cli/services/learning-service.js +2 -1
  79. package/dist/src/cli/services/project-root.js +17 -1
  80. package/dist/src/cli/services/worker-daemon.js +2 -1
  81. package/dist/src/cli/shared/hooks/example-usage.js +3 -2
  82. package/dist/src/cli/shared/hooks/safety/git-commit.js +11 -2
  83. package/dist/src/cli/shared/hooks/session-hooks.js +3 -2
  84. package/dist/src/cli/shared/hooks/task-hooks.js +2 -1
  85. package/dist/src/cli/shared/mcp/session-manager.js +2 -1
  86. package/dist/src/cli/shared/plugins/official/hive-mind-plugin.js +2 -1
  87. package/dist/src/cli/shared/plugins/official/maestro-plugin.js +3 -2
  88. package/dist/src/cli/shared/security/index.js +6 -2
  89. package/dist/src/cli/shared/utils/atomic-file-write.js +9 -1
  90. package/dist/src/cli/shared/utils/id.js +54 -0
  91. package/dist/src/cli/shared/utils/platform.js +36 -5
  92. package/dist/src/cli/spells/commands/destructive-pattern-checker.js +6 -1
  93. package/dist/src/cli/spells/core/dry-run-validator.js +2 -1
  94. package/dist/src/cli/spells/core/interpolation.js +8 -3
  95. package/dist/src/cli/spells/core/permission-resolver.js +2 -2
  96. package/dist/src/cli/spells/core/runner.js +2 -1
  97. package/dist/src/cli/spells/core/shell.js +7 -8
  98. package/dist/src/cli/spells/factory/runner-bridge.js +3 -2
  99. package/dist/src/cli/spells/factory/runner-factory.js +3 -2
  100. package/dist/src/cli/spells/scheduler/scheduler.js +2 -1
  101. package/dist/src/cli/swarm/consensus/gossip.js +2 -1
  102. package/dist/src/cli/swarm/federation-hub.js +5 -4
  103. package/dist/src/cli/swarm/queen-coordinator.js +5 -4
  104. package/dist/src/cli/swarm/shared/events.js +2 -1
  105. package/dist/src/cli/swarm/unified-coordinator.js +3 -2
  106. package/dist/src/cli/version.js +1 -1
  107. package/package.json +2 -2
  108. package/retired-files.json +0 -72
  109. package/dist/src/cli/mcp-tools/coordination-tools.js +0 -86
  110. package/dist/src/cli/shared/security/secure-random.js +0 -142
@@ -24,13 +24,44 @@ export function getShell() {
24
24
  }
25
25
  /**
26
26
  * Escape a shell argument in a platform-appropriate way.
27
- * On Windows: double-quote wrapping with escaped inner quotes.
28
- * On Unix: single-quote wrapping with escaped inner quotes.
27
+ *
28
+ * **This is the canonical implementation.** Every other copy in the tree
29
+ * re-exports it (`spells/core/shell.ts`) or, where a plain `.mjs` cannot import
30
+ * TS, mirrors it with a pointer back here (`harness/consumer-smoke/lib/proc.mjs`).
31
+ *
32
+ * On Windows the wrapping is `"…"` and backslashes matter: under MSVCRT argv
33
+ * parsing a backslash is only special immediately before a `"`, where it escapes
34
+ * it. Escaping quotes alone — the previous behaviour — left a trailing backslash
35
+ * escaping the *closing* quote, so `C:\Users\eric\` became `"C:\Users\eric\"`,
36
+ * the quoted region ran on, and it swallowed the next argument. Windows paths
37
+ * produce that shape constantly (#1419). So: double every run of backslashes
38
+ * that precedes a `"` or terminates the string, then escape the quotes.
39
+ *
40
+ * On Unix the `'\''` idiom is already total — single quotes suppress every other
41
+ * metacharacter — and is unchanged.
42
+ *
43
+ * Scope: this makes the argument survive the C runtime's argv split. It does not
44
+ * neutralise `cmd.exe`'s own `%VAR%` expansion, which happens before the runtime
45
+ * ever sees the string; prefer passing an argv array with `shell: false` when the
46
+ * call site allows it.
29
47
  */
30
48
  export function escapeShellArg(arg) {
31
- if (IS_WINDOWS) {
32
- return '"' + arg.replace(/"/g, '\\"') + '"';
33
- }
49
+ return IS_WINDOWS ? escapeShellArgWindows(arg) : escapeShellArgPosix(arg);
50
+ }
51
+ /**
52
+ * The Windows branch of {@link escapeShellArg}, exported so it can be tested
53
+ * from any host. Rule #1: a Windows-only code path guarded by `IS_WINDOWS` is a
54
+ * path that a Linux CI run never executes, which is how the trailing-backslash
55
+ * defect survived — including in the smoke harness built to catch exactly this.
56
+ */
57
+ export function escapeShellArgWindows(arg) {
58
+ const escaped = arg
59
+ .replace(/(\\*)"/g, '$1$1\\"') // backslash run before a quote: double it, then escape the quote
60
+ .replace(/(\\+)$/, '$1$1'); // backslash run before the closing quote: double it
61
+ return `"${escaped}"`;
62
+ }
63
+ /** The POSIX branch of {@link escapeShellArg}, exported for the same reason. */
64
+ export function escapeShellArgPosix(arg) {
34
65
  return "'" + arg.replace(/'/g, "'\\''") + "'";
35
66
  }
36
67
  //# sourceMappingURL=platform.js.map
@@ -19,8 +19,13 @@ const DENYLIST = [
19
19
  // /lib, /boot, /root, /home (alone — not /home/user/project/dist),
20
20
  // C:\ (Windows root).
21
21
  // End-of-string OR followed by space/wildcard — NOT followed by more path.
22
+ // The flag group is `[^rfRF\W]*[rfRF]\w*`, not `\w*[rfRF]\w*`: forcing the
23
+ // leading run to exclude r/f pins each match to the FIRST r/f in the token, so
24
+ // a flag can be split exactly one way. The ambiguous form inside the outer `*`
25
+ // backtracked exponentially on `rm ` + repeated `-ff\t`, and a safety gate
26
+ // that hangs is a safety gate that is not enforcing (#1418).
22
27
  {
23
- regex: /\brm\s+(?:-\w*[rfRF]\w*\s+)*(?:\/(?:\s|$|\*)|~(?:\/?\s|\/?\*|$)|(?:\/(?:home|etc|usr|var|bin|sbin|lib|boot|root))(?:\s|$|\*|\/\*)|[A-Z]:\\(?:\s|$|\\?\*))/i,
28
+ regex: /\brm\s+(?:-[^rfRF\W]*[rfRF]\w*\s+)*(?:\/(?:\s|$|\*)|~(?:\/?\s|\/?\*|$)|(?:\/(?:home|etc|usr|var|bin|sbin|lib|boot|root))(?:\s|$|\*|\/\*)|[A-Z]:\\(?:\s|$|\\?\*))/i,
24
29
  pattern: 'Recursive delete of root/home/system directories',
25
30
  reason: 'Filesystem wipe — would destroy system or user files',
26
31
  },
@@ -10,6 +10,7 @@ import { resolveArguments } from '../schema/validator.js';
10
10
  import { checkCapabilities, resolveMofloLevel, } from './capability-validator.js';
11
11
  import { collectPrerequisites, checkPrerequisites } from './prerequisite-checker.js';
12
12
  import { analyzeStepPermissions, analyzeSpellPermissions } from './permission-disclosure.js';
13
+ import { generateId } from '../../shared/utils/id.js';
13
14
  /**
14
15
  * Validate a single step for dry-run, returning a report of what WOULD happen.
15
16
  *
@@ -98,7 +99,7 @@ export async function dryRunValidate(definition, resolvedArgs, defValidation, op
98
99
  ? await checkPrerequisites(allPrereqs)
99
100
  : [];
100
101
  const prereqByName = new Map(prereqResults.map(r => [r.name, r]));
101
- const spellId = `dryrun-${Date.now()}`;
102
+ const spellId = generateId('dryrun');
102
103
  const variables = {};
103
104
  const stepReports = [];
104
105
  const env = { registry, definition, options, prereqByName };
@@ -4,6 +4,7 @@
4
4
  * Resolves `{stepId.outputKey}` placeholders in spell step configs.
5
5
  * Nested property access is supported: `{step1.data.nested.value}`.
6
6
  */
7
+ import { escapeShellArgPosix } from '../../shared/utils/platform.js';
7
8
  /**
8
9
  * Matches `{path}` variable references in spell step configs.
9
10
  *
@@ -89,9 +90,13 @@ export function interpolateString(template, context) {
89
90
  * This prevents shell metacharacter injection (`;`, `|`, `` ` ``, `$()`, `&&`, `||`).
90
91
  */
91
92
  export function shellEscapeValue(value) {
92
- // Always use POSIX single-quote escaping — this function is specifically
93
- // for shell interpolation in bash commands (bashCommand hardcodes shell: 'bash')
94
- return "'" + value.replace(/'/g, "'\\''") + "'";
93
+ // Always POSIX single-quote escaping, unconditionally — this function is
94
+ // specifically for shell interpolation in bash commands (bashCommand hardcodes
95
+ // shell: 'bash'), so it must NOT switch to Windows quoting on a Windows host.
96
+ // `escapeShellArgPosix` is exactly that branch, reused rather than re-spelled:
97
+ // this was a third copy of the idiom, and #1419 exists because the second copy
98
+ // went unfixed when the first one did.
99
+ return escapeShellArgPosix(value);
95
100
  }
96
101
  /**
97
102
  * Interpolate `{path}` placeholders with shell-escaped values.
@@ -13,6 +13,7 @@
13
13
  * 1. Explicit `permissionLevel` on the step definition → use directly
14
14
  * 2. Derive from step capabilities: shell → elevated, fs:write → standard, else readonly
15
15
  */
16
+ import { escapeShellArg } from '../../shared/utils/platform.js';
16
17
  export const VALID_PERMISSION_LEVELS = [
17
18
  'readonly', 'standard', 'elevated', 'autonomous',
18
19
  ];
@@ -76,8 +77,7 @@ export function resolvePermissions(explicitLevel, capabilities, additionalTools)
76
77
  */
77
78
  export function buildClaudeCommand(prompt, explicitLevel, capabilities, additionalTools) {
78
79
  const resolved = resolvePermissions(explicitLevel, capabilities, additionalTools);
79
- const escapedPrompt = prompt.replace(/"/g, '\\"');
80
- return `claude ${resolved.cliArgs.join(' ')} -p "${escapedPrompt}"`;
80
+ return `claude ${resolved.cliArgs.join(' ')} -p ${escapeShellArg(prompt)}`;
81
81
  }
82
82
  // ============================================================================
83
83
  // Capability → Permission Level Derivation
@@ -19,6 +19,7 @@ import { resolveEffectiveSandbox, formatSandboxLog, DEFAULT_SANDBOX_CONFIG, } fr
19
19
  import { checkAcceptance, recordAcceptance } from './permission-acceptance.js';
20
20
  import { analyzeSpellPermissions, formatSpellPermissionReport } from './permission-disclosure.js';
21
21
  import { createRunBudget, mergeSpellBudgets, } from './run-budget.js';
22
+ import { generateId } from '../../shared/utils/id.js';
22
23
  /** Spell engine version. Story #285 (epic #287) — workflow-test constant. */
23
24
  export const ENGINE_VERSION = '1.0.0';
24
25
  export class SpellCaster {
@@ -41,7 +42,7 @@ export class SpellCaster {
41
42
  const defValidation = validateSpellDefinition(definition, {
42
43
  knownStepTypes: this.registry.types(),
43
44
  });
44
- const spellId = options.spellId ?? `sp-${Date.now()}`;
45
+ const spellId = options.spellId ?? generateId('sp');
45
46
  if (!defValidation.valid) {
46
47
  return this.failureResult(spellId, startTime, [{
47
48
  code: 'DEFINITION_VALIDATION_FAILED',
@@ -46,13 +46,12 @@ export function execFileAsync(file, args, timeout = 30000) {
46
46
  });
47
47
  }
48
48
  /**
49
- * Escape a string for safe use as a single-quoted shell argument.
50
- * Wraps in single quotes and escapes embedded single quotes.
49
+ * Escape a string for safe use as a shell argument.
50
+ *
51
+ * Re-exported from `shared/utils/platform.ts` rather than redefined: this module
52
+ * carried a near-identical copy, and the Windows branch of that copy had the
53
+ * trailing-backslash defect fixed in #1419. Two implementations meant fixing the
54
+ * same bug twice — or, as happened, once.
51
55
  */
52
- export function escapeShellArg(arg) {
53
- if (process.platform === 'win32') {
54
- return `"${arg.replace(/"/g, '\\"')}"`;
55
- }
56
- return `'${arg.replace(/'/g, "'\\''")}'`;
57
- }
56
+ export { escapeShellArg } from '../../shared/utils/platform.js';
58
57
  //# sourceMappingURL=shell.js.map
@@ -11,6 +11,7 @@
11
11
  import { loadSandboxConfigFromProject } from '../core/platform-sandbox.js';
12
12
  import { createRunner, runSpellFromContent } from './runner-factory.js';
13
13
  import { getDefaultCredentialStore } from '../credentials/default-store.js';
14
+ import { generateId } from '../../shared/utils/id.js';
14
15
  /**
15
16
  * Resolve sandbox config: prefer caller-supplied; fall back to auto-loading
16
17
  * from moflo.yaml at projectRoot. Returns undefined when neither is available
@@ -32,7 +33,7 @@ const activeSpells = new Map();
32
33
  * Run a spell from raw file content (YAML/JSON).
33
34
  */
34
35
  export async function bridgeRunSpell(content, sourceFile, args, options = {}) {
35
- const spellId = `sp-${Date.now()}`;
36
+ const spellId = generateId('sp');
36
37
  const controller = new AbortController();
37
38
  activeSpells.set(spellId, controller);
38
39
  try {
@@ -60,7 +61,7 @@ export async function bridgeRunSpell(content, sourceFile, args, options = {}) {
60
61
  * Run a SpellDefinition directly (for spell_execute).
61
62
  */
62
63
  export async function bridgeExecuteSpell(definition, args, options = {}) {
63
- const spellId = options.spellId ?? `sp-${Date.now()}`;
64
+ const spellId = options.spellId ?? generateId('sp');
64
65
  const controller = new AbortController();
65
66
  activeSpells.set(spellId, controller);
66
67
  try {
@@ -16,6 +16,7 @@ import { loadSandboxConfigFromProject } from '../core/platform-sandbox.js';
16
16
  import { loadSpellBudgetFromProject } from '../core/run-budget.js';
17
17
  import { errorDetail } from '../../shared/utils/error-detail.js';
18
18
  import { getDefaultCredentialStore } from '../credentials/default-store.js';
19
+ import { generateId } from '../../shared/utils/id.js';
19
20
  // ============================================================================
20
21
  // Factory
21
22
  // ============================================================================
@@ -58,7 +59,7 @@ export async function runSpellFromContent(content, sourceFile, options = {}) {
58
59
  }
59
60
  catch (err) {
60
61
  return {
61
- spellId: options.spellId ?? `sp-${Date.now()}`,
62
+ spellId: options.spellId ?? generateId('sp'),
62
63
  success: false,
63
64
  steps: [],
64
65
  outputs: {},
@@ -70,7 +71,7 @@ export async function runSpellFromContent(content, sourceFile, options = {}) {
70
71
  const validation = validateSpellDefinition(definition);
71
72
  if (!validation.valid) {
72
73
  return {
73
- spellId: options.spellId ?? `sp-${Date.now()}`,
74
+ spellId: options.spellId ?? generateId('sp'),
74
75
  success: false,
75
76
  steps: [],
76
77
  outputs: {},
@@ -7,6 +7,7 @@
7
7
  import { computeNextRun } from './cron-parser.js';
8
8
  import { compareMofloLevels } from '../core/capability-validator.js';
9
9
  import { errorDetail } from '../../shared/utils/error-detail.js';
10
+ import { generateId } from '../../shared/utils/id.js';
10
11
  // ============================================================================
11
12
  // Constants
12
13
  // ============================================================================
@@ -135,7 +136,7 @@ export class SpellScheduler {
135
136
  if (nextRunAt === null) {
136
137
  throw new Error('Could not compute next run time from provided schedule');
137
138
  }
138
- const id = `sched-adhoc-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
139
+ const id = generateId('sched-adhoc');
139
140
  const record = {
140
141
  id,
141
142
  spellName: params.spellName,
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { EventEmitter } from 'events';
6
6
  import { SWARM_CONSTANTS, } from '../types.js';
7
+ import { generateId } from '../../shared/utils/id.js';
7
8
  export class GossipConsensus extends EventEmitter {
8
9
  config;
9
10
  node;
@@ -359,7 +360,7 @@ export class GossipConsensus extends EventEmitter {
359
360
  const neighbors = Array.from(this.node.neighbors);
360
361
  const randomNeighbor = neighbors[Math.floor(Math.random() * neighbors.length)];
361
362
  const stateMessage = {
362
- id: `state_${this.node.id}_${Date.now()}`,
363
+ id: generateId(`state_${this.node.id}`, { separator: '_' }),
363
364
  type: 'state',
364
365
  senderId: this.node.id,
365
366
  version: this.node.version,
@@ -24,11 +24,12 @@
24
24
  * @version 3.0.0-alpha.1
25
25
  */
26
26
  import { EventEmitter } from 'events';
27
+ import { generateId } from '../shared/utils/id.js';
27
28
  // ============================================================================
28
29
  // Default Configuration
29
30
  // ============================================================================
30
31
  const DEFAULT_CONFIG = {
31
- federationId: `federation_${Date.now()}`,
32
+ federationId: generateId('federation', { separator: '_' }),
32
33
  maxEphemeralAgents: 100,
33
34
  defaultTTL: 300000, // 5 minutes
34
35
  syncIntervalMs: 30000, // 30 seconds
@@ -264,7 +265,7 @@ export class FederationHub extends EventEmitter {
264
265
  }
265
266
  // Create ephemeral agent
266
267
  const ttl = options.ttl || this.config.defaultTTL;
267
- const agentId = `ephemeral_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
268
+ const agentId = generateId('ephemeral', { separator: '_' });
268
269
  const now = new Date();
269
270
  const agent = {
270
271
  id: agentId,
@@ -389,7 +390,7 @@ export class FederationHub extends EventEmitter {
389
390
  return false;
390
391
  }
391
392
  const message = {
392
- id: `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
393
+ id: generateId('msg', { separator: '_' }),
393
394
  type: 'direct',
394
395
  sourceSwarmId,
395
396
  targetSwarmId,
@@ -435,7 +436,7 @@ export class FederationHub extends EventEmitter {
435
436
  throw new Error('Consensus is disabled');
436
437
  }
437
438
  const proposal = {
438
- id: `proposal_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
439
+ id: generateId('proposal', { separator: '_' }),
439
440
  proposerId,
440
441
  type,
441
442
  value,
@@ -47,6 +47,7 @@ const DEFAULT_CONFIG = {
47
47
  enableFailover: true,
48
48
  maxDelegationAttempts: 3,
49
49
  };
50
+ import { generateId } from '../shared/utils/id.js';
50
51
  // =============================================================================
51
52
  // Queen Coordinator Class
52
53
  // =============================================================================
@@ -932,7 +933,7 @@ export class QueenCoordinator extends EventEmitter {
932
933
  for (const bottleneck of bottlenecks) {
933
934
  if (bottleneck.severity === 'critical' || bottleneck.severity === 'high') {
934
935
  alerts.push({
935
- alertId: `alert_${Date.now()}_${alerts.length}`,
936
+ alertId: generateId('alert', { separator: '_' }),
936
937
  type: bottleneck.severity === 'critical' ? 'critical' : 'error',
937
938
  source: bottleneck.location,
938
939
  message: bottleneck.description,
@@ -947,7 +948,7 @@ export class QueenCoordinator extends EventEmitter {
947
948
  : 1.0;
948
949
  if (avgHealth < 0.5) {
949
950
  alerts.push({
950
- alertId: `alert_${Date.now()}_health`,
951
+ alertId: `${generateId('alert', { separator: '_' })}_health`,
951
952
  type: avgHealth < 0.3 ? 'critical' : 'warning',
952
953
  source: 'swarm',
953
954
  message: `Low average agent health: ${(avgHealth * 100).toFixed(1)}%`,
@@ -961,7 +962,7 @@ export class QueenCoordinator extends EventEmitter {
961
962
  : 0;
962
963
  if (failureRate > this.config.bottleneckThresholds.errorRate) {
963
964
  alerts.push({
964
- alertId: `alert_${Date.now()}_failures`,
965
+ alertId: `${generateId('alert', { separator: '_' })}_failures`,
965
966
  type: failureRate > 0.2 ? 'critical' : 'warning',
966
967
  source: 'tasks',
967
968
  message: `High task failure rate: ${(failureRate * 100).toFixed(1)}%`,
@@ -1275,7 +1276,7 @@ export class QueenCoordinator extends EventEmitter {
1275
1276
  }
1276
1277
  emitEvent(type, data) {
1277
1278
  const event = {
1278
- id: `event_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`,
1279
+ id: generateId('event', { separator: '_' }),
1279
1280
  type,
1280
1281
  source: 'queen-coordinator',
1281
1282
  timestamp: new Date(),
@@ -5,6 +5,7 @@
5
5
  * This file provides a complete event system for standalone operation
6
6
  * without dependency on @moflo/shared
7
7
  */
8
+ import { generateId } from '../../shared/utils/id.js';
8
9
  // =============================================================================
9
10
  // Event Bus Implementation
10
11
  // =============================================================================
@@ -127,7 +128,7 @@ export function createEvent(type, source, payload) {
127
128
  }
128
129
  // Helper function to generate event IDs
129
130
  function generateEventId() {
130
- return `evt-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
131
+ return generateId('evt');
131
132
  }
132
133
  // Helper function to create a base SwarmEvent
133
134
  function createSwarmEvent(type, source, payload) {
@@ -22,6 +22,7 @@ import { MessageBus } from './message-bus.js';
22
22
  import { createAgentPool } from './agent-pool.js';
23
23
  import { createConsensusEngine } from './consensus/index.js';
24
24
  import { fromPersistedTask, isTerminalTaskStatus, } from './swarm-persistence.js';
25
+ import { generateId } from '../shared/utils/id.js';
25
26
  // =============================================================================
26
27
  // 15-Agent Domain Configuration
27
28
  // =============================================================================
@@ -551,7 +552,7 @@ export class UnifiedSwarmCoordinator extends EventEmitter {
551
552
  }
552
553
  createInitialState() {
553
554
  const swarmId = {
554
- id: `swarm_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
555
+ id: generateId('swarm', { separator: '_' }),
555
556
  namespace: 'default',
556
557
  version: '3.0.0',
557
558
  createdAt: new Date(),
@@ -1116,7 +1117,7 @@ export class UnifiedSwarmCoordinator extends EventEmitter {
1116
1117
  }
1117
1118
  emitEvent(type, data) {
1118
1119
  const event = {
1119
- id: `event_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`,
1120
+ id: generateId('event', { separator: '_' }),
1120
1121
  type,
1121
1122
  source: this.state.id.id,
1122
1123
  timestamp: new Date(),
@@ -2,5 +2,5 @@
2
2
  * Auto-generated by build. Do not edit manually.
3
3
  * Source of truth: root package.json → scripts/sync-version.mjs
4
4
  */
5
- export const VERSION = '4.12.4';
5
+ export const VERSION = '4.12.6';
6
6
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moflo",
3
- "version": "4.12.4",
3
+ "version": "4.12.6",
4
4
  "description": "MoFlo — AI agent orchestration for Claude Code. A standalone, opinionated toolkit with semantic memory, learned routing, gates, spells, and the /flo issue-execution skill.",
5
5
  "main": "dist/src/cli/index.js",
6
6
  "type": "module",
@@ -98,7 +98,7 @@
98
98
  "@typescript-eslint/parser": "^8.65.0",
99
99
  "eslint": "^10.8.0",
100
100
  "glob": "^11.1.0",
101
- "moflo": "^4.12.4-rc.10",
101
+ "moflo": "^4.12.5",
102
102
  "tsx": "^4.21.0",
103
103
  "typescript": "^5.9.3",
104
104
  "vitest": "^4.0.0"
@@ -1,13 +1,6 @@
1
1
  {
2
2
  "version": 1,
3
3
  "retired": [
4
- {
5
- "path": ".claude/agents/analysis/code-analyzer.md",
6
- "knownContentHashes": [
7
- "sha256:259bd298e1f6cf297ab5354e4701bec9cf0020bc22a66bba96c09cc580af47f0"
8
- ],
9
- "retiredIn": "2.0.0-alpha.121"
10
- },
11
4
  {
12
5
  "path": ".claude/agents/analysis/code-review/analyze-code-quality.md",
13
6
  "knownContentHashes": [
@@ -16,21 +9,6 @@
16
9
  ],
17
10
  "retiredIn": "4.8.12"
18
11
  },
19
- {
20
- "path": ".claude/agents/architecture/system-design/arch-system-design.md",
21
- "knownContentHashes": [
22
- "sha256:7330ff870b23d2d6c05a415fdd9cc7ee6ff49a2cc48a33eb1962b830106abf3b"
23
- ],
24
- "retiredIn": "3.0.0-alpha.1"
25
- },
26
- {
27
- "path": ".claude/agents/base-template-generator.md",
28
- "knownContentHashes": [
29
- "sha256:1bea126c6853067e650e432b1e5cedf588f3161c4995eb1e2e97d04733e24d83",
30
- "sha256:4b957343021823020828d6d213126243bad177f29984fc09545814b88fcfa87a"
31
- ],
32
- "retiredIn": "2.0.0-alpha.121"
33
- },
34
12
  {
35
13
  "path": ".claude/agents/consensus/byzantine-coordinator.md",
36
14
  "knownContentHashes": [
@@ -96,41 +74,6 @@
96
74
  "retiredIn": "4.9.21",
97
75
  "retiredBy": "#932"
98
76
  },
99
- {
100
- "path": ".claude/agents/core/coder.md",
101
- "knownContentHashes": [
102
- "sha256:fd11f4cf99f74e7db021947e0ecc10f8fd3e5afb357433bcf68058905abf0116"
103
- ],
104
- "retiredIn": "2.0.0-alpha.121"
105
- },
106
- {
107
- "path": ".claude/agents/core/planner.md",
108
- "knownContentHashes": [
109
- "sha256:1ea85a5cf770f62e7e40e612be9fc5d779dd265f77fa942ee6f8d1c3950127c3"
110
- ],
111
- "retiredIn": "2.0.0-alpha.121"
112
- },
113
- {
114
- "path": ".claude/agents/core/researcher.md",
115
- "knownContentHashes": [
116
- "sha256:e486075522aef212f49ab79659130521fe362779daf0919fac17f2d1f16576a6"
117
- ],
118
- "retiredIn": "2.0.0-alpha.121"
119
- },
120
- {
121
- "path": ".claude/agents/core/reviewer.md",
122
- "knownContentHashes": [
123
- "sha256:664518900259644124b28d4b0e92be3ca139fa391920fc0e97b309649bc093fd"
124
- ],
125
- "retiredIn": "2.0.0-alpha.121"
126
- },
127
- {
128
- "path": ".claude/agents/core/tester.md",
129
- "knownContentHashes": [
130
- "sha256:26f05967316ebbda9b96b7262fe80500d158fcd2f75f1adba1d28c99d882f6e7"
131
- ],
132
- "retiredIn": "2.0.0-alpha.121"
133
- },
134
77
  {
135
78
  "path": ".claude/agents/data/ml/data-ml-model.md",
136
79
  "knownContentHashes": [
@@ -150,21 +93,6 @@
150
93
  ],
151
94
  "retiredIn": "4.8.12"
152
95
  },
153
- {
154
- "path": ".claude/agents/devops/ci-cd/ops-cicd-github.md",
155
- "knownContentHashes": [
156
- "sha256:daa1ca3b2e116167dd4d057b64d96bd40c00bfd1d6a3ad3c607dd9129db7a032"
157
- ],
158
- "retiredIn": "3.0.0-alpha.1"
159
- },
160
- {
161
- "path": ".claude/agents/documentation/api-docs/docs-api-openapi.md",
162
- "knownContentHashes": [
163
- "sha256:0a24f98cd97229b746a2f89f2cdfe09fac0ee8dcd757073017fee91e951b7f7f",
164
- "sha256:0cec8892de681a157cb3d56af8e336020dae58ec4a51c0e1dcaf6cfd90c61cd7"
165
- ],
166
- "retiredIn": "3.0.0-alpha.1"
167
- },
168
96
  {
169
97
  "path": ".claude/agents/dual-mode/codex-coordinator.md",
170
98
  "knownContentHashes": [
@@ -1,86 +0,0 @@
1
- /**
2
- * Coordination MCP Tools for CLI
3
- *
4
- * Local sync-state surface — tracks last sync time, sync count, conflicts,
5
- * and pending-change count. Useful for spell orchestration on a single
6
- * machine; not a distributed protocol.
7
- */
8
- import { createJsonStore } from './json-store.js';
9
- const store = createJsonStore({
10
- subdir: 'coordination',
11
- file: 'store.json',
12
- defaults: () => ({
13
- sync: {
14
- lastSync: new Date().toISOString(),
15
- syncCount: 0,
16
- conflicts: 0,
17
- pendingChanges: 0,
18
- },
19
- nodes: {},
20
- version: '3.0.0',
21
- }),
22
- });
23
- export const coordinationTools = [
24
- {
25
- name: 'coordination_sync',
26
- description: 'Synchronize state across nodes',
27
- category: 'coordination',
28
- inputSchema: {
29
- type: 'object',
30
- properties: {
31
- action: { type: 'string', enum: ['status', 'trigger', 'resolve'], description: 'Action to perform' },
32
- force: { type: 'boolean', description: 'Force synchronization' },
33
- conflictResolution: { type: 'string', enum: ['latest', 'merge', 'manual'], description: 'Conflict resolution strategy' },
34
- },
35
- },
36
- handler: async (input) => {
37
- const state = store.load();
38
- const action = input.action || 'status';
39
- if (action === 'status') {
40
- const timeSinceSync = Date.now() - new Date(state.sync.lastSync).getTime();
41
- return {
42
- success: true,
43
- sync: state.sync,
44
- timeSinceSync: `${Math.floor(timeSinceSync / 1000)}s`,
45
- status: state.sync.conflicts > 0 ? 'conflicts' : state.sync.pendingChanges > 0 ? 'pending' : 'synced',
46
- };
47
- }
48
- if (action === 'trigger') {
49
- state.sync.syncCount++;
50
- state.sync.lastSync = new Date().toISOString();
51
- state.sync.pendingChanges = 0;
52
- // Simulate sync
53
- await new Promise(resolve => setTimeout(resolve, 50));
54
- store.save(state);
55
- return {
56
- success: true,
57
- action: 'synchronized',
58
- syncCount: state.sync.syncCount,
59
- syncedAt: state.sync.lastSync,
60
- nodesSync: Object.keys(state.nodes).length,
61
- };
62
- }
63
- if (action === 'resolve') {
64
- const strategy = input.conflictResolution || 'latest';
65
- if (state.sync.conflicts > 0) {
66
- const resolved = state.sync.conflicts;
67
- state.sync.conflicts = 0;
68
- store.save(state);
69
- return {
70
- success: true,
71
- action: 'resolved',
72
- strategy,
73
- conflictsResolved: resolved,
74
- };
75
- }
76
- return {
77
- success: true,
78
- action: 'resolve',
79
- message: 'No conflicts to resolve',
80
- };
81
- }
82
- return { success: false, error: 'Unknown action' };
83
- },
84
- },
85
- ];
86
- //# sourceMappingURL=coordination-tools.js.map