moflo 4.9.19 → 4.9.21
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/.claude/commands/{simplify.md → flo-simplify.md} +4 -4
- package/.claude/guidance/shipped/moflo-agent-rules.md +172 -0
- package/.claude/guidance/shipped/moflo-claude-swarm-cohesion.md +73 -265
- package/.claude/guidance/shipped/moflo-cli-reference.md +6 -6
- package/.claude/guidance/shipped/moflo-core-guidance.md +66 -184
- package/.claude/guidance/shipped/moflo-cross-platform.md +1 -1
- package/.claude/guidance/shipped/moflo-error-handling.md +3 -3
- package/.claude/guidance/shipped/moflo-guidance-rules.md +17 -7
- package/.claude/guidance/shipped/moflo-memory-strategy.md +76 -182
- package/.claude/guidance/shipped/moflo-memorydb-maintenance.md +6 -8
- package/.claude/guidance/shipped/moflo-settings-injection.md +7 -9
- package/.claude/guidance/shipped/moflo-source-hygiene.md +5 -5
- package/.claude/guidance/shipped/moflo-spell-connectors.md +3 -4
- package/.claude/guidance/shipped/moflo-spell-custom-steps.md +3 -4
- package/.claude/guidance/shipped/moflo-spell-engine.md +40 -162
- package/.claude/guidance/shipped/moflo-spell-runner.md +134 -0
- package/.claude/guidance/shipped/moflo-spell-sandboxing.md +10 -57
- package/.claude/guidance/shipped/moflo-spell-troubleshooting.md +149 -0
- package/.claude/guidance/shipped/moflo-subagents.md +43 -114
- package/.claude/guidance/shipped/moflo-task-icons.md +4 -4
- package/.claude/guidance/shipped/moflo-user-facing-language.md +3 -3
- package/.claude/guidance/shipped/moflo-verbose-command-filtering.md +3 -3
- package/.claude/guidance/shipped/moflo-yaml-reference.md +4 -5
- package/.claude/helpers/gate.cjs +124 -14
- package/.claude/helpers/prompt-hook.mjs +4 -38
- package/.claude/helpers/simplify-classify.cjs +32 -11
- package/.claude/helpers/subagent-bootstrap.json +1 -1
- package/.claude/helpers/subagent-start.cjs +1 -1
- package/.claude/skills/connector-builder/SKILL.md +42 -429
- package/.claude/skills/connector-builder/templates/connector.md +189 -0
- package/.claude/skills/connector-builder/templates/step-command.md +176 -0
- package/.claude/skills/eldar/SKILL.md +7 -7
- package/.claude/skills/fl/SKILL.md +3 -3
- package/.claude/skills/fl/execution-modes.md +3 -3
- package/.claude/skills/fl/phases.md +3 -3
- package/.claude/skills/{simplify → flo-simplify}/SKILL.md +11 -11
- package/.claude/skills/guidance/SKILL.md +17 -9
- package/.claude/skills/memory-patterns/SKILL.md +1 -1
- package/.claude/skills/publish/SKILL.md +121 -36
- package/.claude/skills/reset-epic/SKILL.md +2 -2
- package/.claude/skills/spell-builder/SKILL.md +39 -226
- package/.claude/skills/spell-builder/architecture.md +1 -1
- package/.claude/skills/spell-builder/permissions.md +107 -0
- package/.claude/skills/spell-builder/preflight.md +101 -0
- package/.claude/skills/spell-schedule/SKILL.md +2 -3
- package/bin/gate.cjs +124 -14
- package/bin/prompt-hook.mjs +4 -38
- package/bin/session-start-launcher.mjs +66 -1
- package/bin/setup-project.mjs +63 -69
- package/bin/simplify-classify.cjs +32 -11
- package/dist/src/cli/commands/doctor-checks-deep.js +4 -0
- package/dist/src/cli/init/claudemd-generator.js +30 -33
- package/dist/src/cli/init/executor.js +28 -16
- package/dist/src/cli/init/helpers-generator.js +101 -51
- package/dist/src/cli/init/moflo-init.js +41 -114
- package/dist/src/cli/init/settings-generator.js +32 -14
- package/dist/src/cli/services/hook-block-hash.js +7 -2
- package/dist/src/cli/services/hook-wiring.js +86 -3
- package/dist/src/cli/services/subagent-bootstrap.js +1 -1
- package/dist/src/cli/version.js +1 -1
- package/package.json +2 -2
- package/scripts/post-install-bootstrap.mjs +19 -0
- package/.claude/guidance/shipped/moflo-session-start.md +0 -154
- package/.claude/guidance/shipped/moflo-spell-engine-architecture.md +0 -145
- package/.claude/skills/browser/SKILL.md +0 -204
- package/.claude/skills/github-code-review/SKILL.md +0 -1140
- package/.claude/skills/github-multi-repo/SKILL.md +0 -866
- package/.claude/skills/github-project-management/SKILL.md +0 -1272
- package/.claude/skills/github-release-management/SKILL.md +0 -1074
- package/.claude/skills/github-workflow-automation/SKILL.md +0 -1060
- package/.claude/skills/hive-mind-advanced/SKILL.md +0 -712
- package/.claude/skills/hooks-automation/SKILL.md +0 -1193
- package/.claude/skills/pair-programming/SKILL.md +0 -1202
- package/.claude/skills/performance-analysis/SKILL.md +0 -563
- package/.claude/skills/skill-builder/SKILL.md +0 -910
- package/.claude/skills/sparc-methodology/SKILL.md +0 -904
- package/.claude/skills/stream-chain/SKILL.md +0 -563
- package/.claude/skills/swarm-advanced/SKILL.md +0 -811
- package/.claude/skills/swarm-orchestration/SKILL.md +0 -179
- package/.claude/skills/verification-quality/SKILL.md +0 -649
- package/.claude/skills/worker-benchmarks/skill.md +0 -135
- package/.claude/skills/worker-integration/skill.md +0 -154
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Spell Troubleshooting — Sandbox, Network, and Permission Failures
|
|
2
|
+
|
|
3
|
+
**Purpose:** Diagnostic playbook for spell step failures that look like environmental issues but are actually capability/sandbox boundaries. Reference this when a step "should work" but produces DNS errors, silent no-ops, or confusing downstream failures. Pair with `.claude/guidance/moflo-spell-sandboxing.md` for the underlying enforcement model.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Bash Step Fails With DNS / SSH Resolution Errors
|
|
8
|
+
|
|
9
|
+
The single most common spell failure mode. The step works fine in your normal shell, then fails inside a spell with what looks like a network/DNS problem.
|
|
10
|
+
|
|
11
|
+
### Typical Error Messages
|
|
12
|
+
|
|
13
|
+
- `ssh: Could not resolve hostname github.com: Temporary failure in name resolution`
|
|
14
|
+
- `fatal: Could not read from remote repository.`
|
|
15
|
+
- `curl: (6) Could not resolve host ...`
|
|
16
|
+
- `getaddrinfo ENOTFOUND ...`
|
|
17
|
+
- Any other DNS/connection failure where the **same command works in your normal shell**.
|
|
18
|
+
|
|
19
|
+
### Tell-Tale Clue
|
|
20
|
+
|
|
21
|
+
The error mentions `Temporary failure in name resolution` — a **glibc-specific** wording. That means the step is running inside a Linux sandbox (`bwrap` on Linux / WSL), **not** your outer shell. Git Bash or PowerShell won't produce that exact message.
|
|
22
|
+
|
|
23
|
+
### Root Cause
|
|
24
|
+
|
|
25
|
+
`src/cli/spells/core/bwrap-sandbox.ts` isolates the network by default:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
if (!hasNet && !needsToolHomeAccess(options.permissionLevel)) {
|
|
29
|
+
args.push('--unshare-net'); // ← no network, no DNS
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
A bash step gets network access **only when one of these is true**:
|
|
34
|
+
|
|
35
|
+
1. The step declares a `net` capability, **or**
|
|
36
|
+
2. The step's `permissionLevel` is `elevated` or `autonomous`.
|
|
37
|
+
|
|
38
|
+
If neither applies, bwrap runs the command in a namespace with `--unshare-net`, and DNS silently fails. **There is no log line announcing the network was taken away** — you just see the command's own DNS error.
|
|
39
|
+
|
|
40
|
+
### Fix
|
|
41
|
+
|
|
42
|
+
For any bash step that does `git pull` / `git push` / `git fetch`, `gh` API calls, `curl`, `npm install`, or any other outbound network call:
|
|
43
|
+
|
|
44
|
+
```yaml
|
|
45
|
+
- id: create-branch
|
|
46
|
+
type: bash
|
|
47
|
+
permissionLevel: elevated # ← grants network in bwrap
|
|
48
|
+
config:
|
|
49
|
+
command: "git pull origin main && ..."
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Or declare the `net` capability explicitly if the step doesn't need the full `elevated` profile. **Note:** `bash-command.ts` must include `net` in its declared capabilities for the engine to accept the grant — otherwise you'll see:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
Capability violation: step type "bash" does not declare capability "net"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Quick Diagnosis Checklist
|
|
59
|
+
|
|
60
|
+
When a spell's bash step can't reach the network, walk through these in order:
|
|
61
|
+
|
|
62
|
+
| # | Question | If yes |
|
|
63
|
+
|---|----------|--------|
|
|
64
|
+
| 1 | Does the same command work in your outer shell? | Sandbox-related, not config — go to #2 |
|
|
65
|
+
| 2 | Is the error wording glibc-style (`Temporary failure in name resolution`)? | bwrap is involved — go to #3 |
|
|
66
|
+
| 3 | Does the failing step have `permissionLevel: elevated` or a `net` capability? | If no, add one and retry |
|
|
67
|
+
| 4 | Does the multi-command step start with `set -e`? | If no, add it (see § Multi-Command `set -e` Traps below) |
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Multi-Command `set -e` Traps
|
|
72
|
+
|
|
73
|
+
A bash step that chains multiple statements without `set -e` will **return exit code 0 even when the real work failed**, producing confusing errors several steps later.
|
|
74
|
+
|
|
75
|
+
### Symptom
|
|
76
|
+
|
|
77
|
+
A spell step appears to succeed (`exitCode: 0`), but a later step fails with something that should have been impossible — typically:
|
|
78
|
+
|
|
79
|
+
- `pathspec did not match` on a branch that was never created
|
|
80
|
+
- `nothing to commit` when you expected staged changes
|
|
81
|
+
- File operations on paths that don't exist
|
|
82
|
+
|
|
83
|
+
### Root Cause
|
|
84
|
+
|
|
85
|
+
Without `set -e`, a multi-command bash step like this:
|
|
86
|
+
|
|
87
|
+
```yaml
|
|
88
|
+
- id: prep-branch
|
|
89
|
+
type: bash
|
|
90
|
+
config:
|
|
91
|
+
command: "git pull origin main && git checkout -b feat/x && git stash pop || true"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
…will mask a failure in `git pull` (e.g. blocked by `--unshare-net`) because the trailing `git stash pop || true` returns 0 for the whole step. Downstream steps assume the branch exists and produce the confusing `pathspec` error.
|
|
95
|
+
|
|
96
|
+
### Fix
|
|
97
|
+
|
|
98
|
+
Lead every multi-command bash step with `set -e`:
|
|
99
|
+
|
|
100
|
+
```yaml
|
|
101
|
+
- id: prep-branch
|
|
102
|
+
type: bash
|
|
103
|
+
permissionLevel: elevated
|
|
104
|
+
config:
|
|
105
|
+
command: |
|
|
106
|
+
set -e
|
|
107
|
+
git pull origin main
|
|
108
|
+
git checkout -b feat/x
|
|
109
|
+
git stash pop || true # only this one is allowed to fail
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`set -e` makes the shell exit on any non-zero status, surfacing the real failure at the right step.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Capability Violation Errors
|
|
117
|
+
|
|
118
|
+
When a spell YAML restricts capabilities a command doesn't declare, or grants new types beyond the command's defaults, the runner blocks execution before the step runs.
|
|
119
|
+
|
|
120
|
+
| Error | Meaning | Fix |
|
|
121
|
+
|-------|---------|-----|
|
|
122
|
+
| `Capability violation: step type "X" does not declare capability "Y"` | YAML restricts a capability the step command doesn't list | Add `Y` to the step command's `capabilities` array (in code), or remove the restriction from YAML |
|
|
123
|
+
| `CAPABILITY_DENIED at runtime` | A command tried to access a path/host outside its effective scope | Tighten the command, or widen the YAML capability scope to include the resource |
|
|
124
|
+
|
|
125
|
+
See `.claude/guidance/moflo-spell-sandboxing.md` § Enforcement at Runtime for the two-layer enforcement model.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Step Silently No-Ops
|
|
130
|
+
|
|
131
|
+
A step appears to run (`exitCode: 0`), produces no output, and downstream steps act as if no work happened.
|
|
132
|
+
|
|
133
|
+
| Likely cause | Diagnostic |
|
|
134
|
+
|--------------|------------|
|
|
135
|
+
| Command writes to stdout but bwrap blocks the working directory | Check `permissionLevel`; bwrap restricts `fs:write` to declared scopes |
|
|
136
|
+
| Variable interpolation produced an empty string | Run with `dryRun: true` to see resolved configs (see `moflo-spell-runner.md`) |
|
|
137
|
+
| `continueOnError: true` is hiding a real failure | Remove `continueOnError` temporarily, re-run, inspect error output |
|
|
138
|
+
| Trailing `|| true` on the only critical statement | Restructure with `set -e` and place `|| true` only on cleanup statements |
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## See Also
|
|
143
|
+
|
|
144
|
+
- `.claude/guidance/moflo-spell-sandboxing.md` — Capability types, enforcement layers, permission levels (the model these failures exercise)
|
|
145
|
+
- `.claude/guidance/moflo-spell-engine.md` — Step definition format and types
|
|
146
|
+
- `.claude/guidance/moflo-spell-runner.md` — Dry-run validation, error codes, pause/resume
|
|
147
|
+
- `.claude/guidance/moflo-yaml-reference.md` — `sandbox:` block in `moflo.yaml` (master toggle, tier selection)
|
|
148
|
+
- `src/cli/spells/core/bwrap-sandbox.ts` — Source for `--unshare-net` and namespace setup
|
|
149
|
+
- `src/cli/spells/core/permission-resolver.ts` — Capability → permission level derivation
|
|
@@ -1,150 +1,79 @@
|
|
|
1
|
-
# MoFlo Subagents
|
|
1
|
+
# MoFlo Subagents — Spawn Protocol
|
|
2
2
|
|
|
3
|
-
**Purpose:**
|
|
3
|
+
**Purpose:** Steps every subagent MUST run when spawned by a coordinator. The single-sentence directive injected by `SubagentStart` (see `.claude/helpers/subagent-bootstrap.json`) tells every subagent to memory-search first, then follow this protocol. Universal coding/coordination rules every agent (coordinator OR subagent) shares live in `.claude/guidance/moflo-agent-rules.md` — read those after Step 1.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
## 1
|
|
7
|
+
## Step 1: Search Memory FIRST
|
|
8
8
|
|
|
9
|
-
**Before reading any files or exploring code, search memory
|
|
9
|
+
**Before reading any files or exploring code, search memory.** This is the bootstrap action — moflo's gates will block your `Glob`/`Grep`/`Read` calls until you do.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
| Namespace | When to search | What it returns |
|
|
14
|
-
|-----------|---------------|-----------------|
|
|
15
|
-
| `guidance` | always | Guidance docs, coding rules, domain context |
|
|
16
|
-
| `patterns` | always | Learned patterns from previous task execution |
|
|
17
|
-
| `learnings` | always | User-directed decisions + distilled insights (post-mortems, gotchas, lessons learned) |
|
|
18
|
-
| `code-map` | navigating code | Project overviews, directory contents, type-to-file mappings |
|
|
19
|
-
| `tests` | test/coverage queries | Indexed test inventory — pinpoint specs and coverage for a given function/module |
|
|
20
|
-
|
|
21
|
-
**Always search `patterns` and `learnings` alongside `guidance`.** Patterns hold solutions to already-solved problems; learnings hold incident insights and user-stated decisions. Skipping either means repeating past mistakes or violating standing decisions.
|
|
22
|
-
|
|
23
|
-
**Search `code-map` BEFORE using Glob/Grep for navigation.** It's faster and returns structured results including file-level type mappings.
|
|
24
|
-
|
|
25
|
-
**Search `tests` when looking for test coverage** of a function, module, or behavior — it indexes the test tree separately so you can pinpoint specs without grepping the whole repo.
|
|
26
|
-
|
|
27
|
-
### Option A: MCP Tools (Preferred)
|
|
28
|
-
|
|
29
|
-
If you have MCP tools available (check for `mcp__moflo__*`), use them directly:
|
|
30
|
-
|
|
31
|
-
| Tool | Purpose |
|
|
32
|
-
|------|---------|
|
|
33
|
-
| `mcp__moflo__memory_search` | Semantic search with domain-aware embeddings |
|
|
34
|
-
| `mcp__moflo__memory_store` | Store patterns with auto-vectorization |
|
|
35
|
-
| `mcp__moflo__hooks_route` | Get agent routing suggestions |
|
|
36
|
-
|
|
37
|
-
### Option B: CLI via Bash
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
npx flo memory search --query "[describe your task]" --namespace guidance --limit 5
|
|
11
|
+
```
|
|
12
|
+
mcp__moflo__memory_search query: "[describe your task]" namespace: "guidance"
|
|
41
13
|
```
|
|
42
14
|
|
|
43
|
-
|
|
44
|
-
|-----------------------|------------------|---------------|
|
|
45
|
-
| Database/entities | `guidance` + `patterns` + `learnings` | `"database entity migration"` |
|
|
46
|
-
| Frontend components | `guidance` + `patterns` + `learnings` | `"React frontend component"` |
|
|
47
|
-
| API endpoints | `guidance` + `patterns` + `learnings` | `"API route endpoint pattern"` |
|
|
48
|
-
| Authentication | `guidance` + `patterns` + `learnings` | `"auth middleware JWT"` |
|
|
49
|
-
| Prior solutions/gotchas | `patterns` + `learnings` | `"audit log service pattern"` |
|
|
50
|
-
| Past incident/lesson | `learnings` | `"windows postinstall file locks"` |
|
|
51
|
-
| Where is a file/type? | `code-map` | `"CompanyEntity file location"` |
|
|
52
|
-
| What's in a directory? | `code-map` | `"back-office api routes"` |
|
|
53
|
-
| Tests for a function | `tests` | `"audit log service tests"` |
|
|
54
|
-
| Coverage for a module | `tests` | `"auth middleware test cases"` |
|
|
55
|
-
|
|
56
|
-
Use results with score > 0.3. If no good results, fall back to reading project guidance docs.
|
|
57
|
-
|
|
58
|
-
---
|
|
59
|
-
|
|
60
|
-
## 2. Check for Project-Specific Overrides
|
|
15
|
+
Run the search **at least three times** — once each against `guidance`, `patterns`, and `learnings`. Patterns hold prior solutions; learnings hold standing decisions and post-mortem insights. Skipping either repeats past mistakes. Add `code-map` when navigating code, `tests` when looking for test coverage.
|
|
61
16
|
|
|
62
|
-
|
|
17
|
+
CLI fallback when MCP is unavailable: `npx flo memory search --query "..." --namespace guidance --limit 5`.
|
|
63
18
|
|
|
64
|
-
|
|
19
|
+
The full namespace reference, query examples by domain, and tool catalog live in `.claude/guidance/moflo-agent-rules.md` § Memory-First Protocol — read that next.
|
|
65
20
|
|
|
66
21
|
---
|
|
67
22
|
|
|
68
|
-
##
|
|
69
|
-
|
|
70
|
-
### Memory Protocol
|
|
71
|
-
- Search memory before exploring files
|
|
72
|
-
- Store discoveries back to memory when done
|
|
73
|
-
- Use `patterns` namespace for solutions and gotchas
|
|
74
|
-
- Use `learnings` namespace for architectural choices, user-requested decisions, and distilled insights (`knowledge` is a deprecated alias — writes are auto-redirected)
|
|
23
|
+
## Step 2: Apply Universal Agent Rules
|
|
75
24
|
|
|
76
|
-
|
|
77
|
-
- Use conventional commit prefixes: `feat:`, `fix:`, `refactor:`, `test:`, `chore:`
|
|
78
|
-
- Use branch prefixes: `feature/`, `fix/`, `refactor/`
|
|
79
|
-
- Use kebab-case for branch names
|
|
25
|
+
Every moflo agent — coordinator or subagent — must follow `.claude/guidance/moflo-agent-rules.md`. The most load-bearing rules for subagents specifically:
|
|
80
26
|
|
|
81
|
-
|
|
82
|
-
|
|
27
|
+
| Rule | Detail |
|
|
28
|
+
|------|--------|
|
|
29
|
+
| **Task Icons** | `TaskCreate` MUST use **ICON + [Role]** in `subject` and `activeForm` — see `.claude/guidance/moflo-task-icons.md`. Example: `🧪 [Tester] Run unit tests` / activeForm: `🧪 Running unit tests` |
|
|
30
|
+
| **PR target repo (CRITICAL)** | Never run bare `gh pr create` in a forked repo — it defaults to upstream. Always pass `--repo "$REPO"`. Full workflow in `moflo-agent-rules.md` |
|
|
31
|
+
| **MCP-first tool selection** | Prefer `mcp__moflo__*` tools over `npx flo` CLI. CLI is fallback only |
|
|
32
|
+
| **Build & test after changes** | Never leave failing tests; fix red signals at the source |
|
|
83
33
|
|
|
84
|
-
|
|
85
|
-
```bash
|
|
86
|
-
# 1. Determine the correct repo from the origin remote
|
|
87
|
-
REPO=$(git remote get-url origin | sed 's|.*github.com[:/]||;s|\.git$||')
|
|
88
|
-
|
|
89
|
-
# 2. ALWAYS pass --repo to gh pr create
|
|
90
|
-
gh pr create --repo "$REPO" --title "..." --body "..."
|
|
91
|
-
|
|
92
|
-
# 3. For merge: also pass --repo
|
|
93
|
-
gh pr merge <number> --repo "$REPO" --squash
|
|
94
|
-
```
|
|
34
|
+
The full set (git/branch conventions, file organization, build/test discipline, storing discoveries) is in `.claude/guidance/moflo-agent-rules.md`.
|
|
95
35
|
|
|
96
|
-
|
|
36
|
+
---
|
|
97
37
|
|
|
98
|
-
|
|
99
|
-
- Never save working files to repository root
|
|
100
|
-
- Keep changes focused (3-10 files)
|
|
101
|
-
- Stay within feature scope
|
|
38
|
+
## Step 3: Check for Project-Specific Overrides
|
|
102
39
|
|
|
103
|
-
|
|
104
|
-
- Build and test after code changes
|
|
105
|
-
- Never leave failing tests
|
|
40
|
+
Claude Code automatically loads all `.claude/guidance/*.md` files into your context. If the consuming project has its own guidance files (domain rules, entity patterns, tech-stack conventions), they're already available — no need to read them manually.
|
|
106
41
|
|
|
107
|
-
|
|
108
|
-
- `TaskCreate` MUST use **ICON + [Role]** in `subject` and `activeForm`
|
|
109
|
-
- Full icon map: `.claude/guidance/shipped/moflo-task-icons.md`
|
|
110
|
-
- Example: `🧪 [Tester] Run unit tests` / activeForm: `🧪 Running unit tests`
|
|
42
|
+
**Project-specific guidance always takes precedence over generic MoFlo guidance.**
|
|
111
43
|
|
|
112
44
|
---
|
|
113
45
|
|
|
114
|
-
## 4
|
|
46
|
+
## Step 4: Store Discoveries Before Reporting
|
|
115
47
|
|
|
116
|
-
|
|
48
|
+
Before signing off your work, store anything useful you discovered during the task. Future agents shouldn't have to re-discover what you already learned.
|
|
117
49
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
key: "brief-descriptive-key"
|
|
123
|
-
value: "1-2 sentence insight"
|
|
124
|
-
```
|
|
50
|
+
| Namespace | What to store |
|
|
51
|
+
|-----------|---------------|
|
|
52
|
+
| `patterns` | Solutions to tricky bugs, gotchas, workarounds |
|
|
53
|
+
| `learnings` | Architectural choices, user-stated decisions, post-mortem insights |
|
|
125
54
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
npx flo memory store --namespace patterns --key "brief-descriptive-key" --value "1-2 sentence insight"
|
|
129
|
-
```
|
|
55
|
+
**Store:** Patterns that worked, gotchas you hit, workarounds for limitations.
|
|
56
|
+
**Skip:** Generic summaries of retrieved guidance, restated rules, trivial file-location notes.
|
|
130
57
|
|
|
131
|
-
|
|
132
|
-
**Skip:** Summaries of retrieved guidance, general rules, file locations
|
|
58
|
+
See `.claude/guidance/moflo-agent-rules.md` § Storing Discoveries for the full MCP/CLI invocation patterns.
|
|
133
59
|
|
|
134
60
|
---
|
|
135
61
|
|
|
136
|
-
## 5
|
|
62
|
+
## Step 5: When Complete
|
|
63
|
+
|
|
64
|
+
1. Report findings to the coordinator
|
|
65
|
+
2. Confirm any discoveries are stored (Step 4)
|
|
66
|
+
3. The coordinator will mark your task `completed` via `TaskUpdate`
|
|
137
67
|
|
|
138
|
-
|
|
139
|
-
2. Store learnings if you discovered something new
|
|
140
|
-
3. Coordinator will mark your task as completed
|
|
68
|
+
Do not mark your own task completed — that's the coordinator's responsibility.
|
|
141
69
|
|
|
142
70
|
---
|
|
143
71
|
|
|
144
72
|
## See Also
|
|
145
73
|
|
|
146
|
-
- `.claude/guidance/
|
|
147
|
-
- `.claude/guidance/
|
|
148
|
-
- `.claude/guidance/
|
|
149
|
-
- `.claude/guidance/
|
|
150
|
-
- `.claude/guidance/
|
|
74
|
+
- `.claude/guidance/moflo-agent-rules.md` — Universal rules every agent (coordinator OR subagent) shares
|
|
75
|
+
- `.claude/guidance/moflo-task-icons.md` — Mandatory ICON + [Role] format for every `TaskCreate` and `Agent` description
|
|
76
|
+
- `.claude/guidance/moflo-claude-swarm-cohesion.md` — How task lists and swarm coordinators cooperate when subagents are spawned in batches
|
|
77
|
+
- `.claude/guidance/moflo-memory-strategy.md` — Memory architecture, namespaces, search patterns
|
|
78
|
+
- `.claude/guidance/moflo-memorydb-maintenance.md` — How memory namespaces are populated and refreshed
|
|
79
|
+
- `.claude/guidance/moflo-core-guidance.md` — Full CLI/MCP reference including the spell gates that block subagent spawn before memory is searched
|
|
@@ -66,7 +66,7 @@ The spinner is the primary visual feedback during agent execution. Without icons
|
|
|
66
66
|
|
|
67
67
|
## See Also
|
|
68
68
|
|
|
69
|
-
- `.claude/guidance/
|
|
70
|
-
- `.claude/guidance/
|
|
71
|
-
- `.claude/guidance/
|
|
72
|
-
- `.claude/guidance/
|
|
69
|
+
- `.claude/guidance/moflo-subagents.md` — Subagent protocol; `TaskCreate`/`Agent` icon rule is enforced as part of the spawning checklist
|
|
70
|
+
- `.claude/guidance/moflo-claude-swarm-cohesion.md` — How task lists and swarms cooperate; icons distinguish swarm-spawned vs single-agent work
|
|
71
|
+
- `.claude/guidance/moflo-user-facing-language.md` — Companion UX rule for any text shown to end users
|
|
72
|
+
- `.claude/guidance/moflo-core-guidance.md` — Spell Gate that enforces icon format on `TaskCreate`
|
|
@@ -37,6 +37,6 @@
|
|
|
37
37
|
|
|
38
38
|
## See Also
|
|
39
39
|
|
|
40
|
-
- `.claude/guidance/
|
|
41
|
-
- `.claude/guidance/
|
|
42
|
-
- `.claude/guidance/
|
|
40
|
+
- `.claude/guidance/moflo-task-icons.md` — Companion UX rule: spinner text must use ICON + [Role] so non-technical users can identify the working agent
|
|
41
|
+
- `.claude/guidance/moflo-spell-sandboxing.md` — Permission disclosure output where this language rule has the largest user-visible surface
|
|
42
|
+
- `.claude/guidance/moflo-error-handling.md` — Sibling rule for what error messages must contain; this doc governs how those messages are phrased
|
|
@@ -35,11 +35,11 @@ npm run build -- --verbose 2>&1 | grep -E "error TS|Failed|Cannot find"
|
|
|
35
35
|
|
|
36
36
|
## Why It Matters
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
A representative incident burned ~25K tokens across 5 tee-then-grep round-trips where a single grep-at-source would have surfaced the same signal once. Filtering at source is not an optimization — it is the default shape for any verbose command whose full output you do not need in your context.
|
|
39
39
|
|
|
40
40
|
---
|
|
41
41
|
|
|
42
42
|
## See Also
|
|
43
43
|
|
|
44
|
-
- `.claude/guidance/
|
|
45
|
-
- `.claude/guidance/
|
|
44
|
+
- `.claude/guidance/moflo-core-guidance.md` — Hub for moflo's CLI/MCP surface and runtime conventions
|
|
45
|
+
- `.claude/guidance/moflo-memory-strategy.md` — Companion rules on RAG indexing and context discipline
|
|
@@ -184,8 +184,7 @@ Global registration is useful for ad-hoc projects where you don't want to commit
|
|
|
184
184
|
|
|
185
185
|
## See Also
|
|
186
186
|
|
|
187
|
-
- `.claude/guidance/
|
|
188
|
-
- `.claude/guidance/
|
|
189
|
-
- `.claude/guidance/
|
|
190
|
-
- `.claude/guidance/
|
|
191
|
-
- `.claude/guidance/shipped/moflo-settings-injection.md` — What moflo writes into `.claude/settings.json` (the hook wiring; complementary to `moflo.yaml` toggles)
|
|
187
|
+
- `.claude/guidance/moflo-core-guidance.md` — Hub: getting started, anti-drift defaults, troubleshooting
|
|
188
|
+
- `.claude/guidance/moflo-cli-reference.md` — Commands, agents, hooks, hive-mind, ruvector — the surfaces this config gates
|
|
189
|
+
- `.claude/guidance/moflo-spell-sandboxing.md` — What `sandbox:` actually does at the bash-step boundary, with capability/permission interaction
|
|
190
|
+
- `.claude/guidance/moflo-settings-injection.md` — What moflo writes into `.claude/settings.json` (the hook wiring; complementary to `moflo.yaml` toggles)
|
package/.claude/helpers/gate.cjs
CHANGED
|
@@ -7,7 +7,7 @@ var cp = require('child_process');
|
|
|
7
7
|
var PROJECT_DIR = (process.env.CLAUDE_PROJECT_DIR || process.cwd()).replace(/^\/([a-z])\//i, '$1:/');
|
|
8
8
|
var STATE_FILE = path.join(PROJECT_DIR, '.claude', 'workflow-state.json');
|
|
9
9
|
|
|
10
|
-
var STATE_DEFAULTS = { tasksCreated: false, taskCount: 0, memorySearched: false, memorySearchedBy: {}, memoryRequired: true, learningsStored: false, testsRun: false, simplifyRun: false, simplifySnapshotSha: null, interactionCount: 0, sessionStart: null, lastBlockedAt: null };
|
|
10
|
+
var STATE_DEFAULTS = { tasksCreated: false, taskCount: 0, memorySearched: false, memorySearchedBy: {}, memoryRequired: true, learningsStored: false, testsRun: false, simplifyRun: false, simplifySnapshotSha: null, interactionCount: 0, sessionStart: null, lastBlockedAt: null, lastNamespaceHint: '', lastNamespaceHintEmittedBy: {} };
|
|
11
11
|
|
|
12
12
|
// Per-actor memory-search tracking (#838). The legacy `memorySearched` boolean
|
|
13
13
|
// is session-wide, so once the parent searches memory, every spawned subagent
|
|
@@ -83,6 +83,78 @@ var EXEMPT = ['.claude/', '.claude\\', 'CLAUDE.md', 'MEMORY.md', 'workflow-state
|
|
|
83
83
|
var DANGEROUS = ['rm -rf /', 'format c:', 'del /s /q c:\\', ':(){:|:&};:', 'mkfs.', '> /dev/sda'];
|
|
84
84
|
var DIRECTIVE_RE = /^(yes|no|yeah|yep|nope|sure|ok|okay|correct|right|exactly|perfect)\b/i;
|
|
85
85
|
var TASK_RE = /\b(fix|bug|error|implement|add|create|build|write|refactor|debug|test|feature|issue|security|optimi)\b/i;
|
|
86
|
+
|
|
87
|
+
// Namespace classification (#931). The hint used to be emitted on every prompt
|
|
88
|
+
// by prompt-hook.mjs which cost ~40 tokens × every prompt × every consumer.
|
|
89
|
+
// Now we classify here, store on workflow-state, and let check-before-agent
|
|
90
|
+
// emit it once when Claude is actually about to spawn an agent.
|
|
91
|
+
//
|
|
92
|
+
// SYNC: these regexes + classifyNamespaceHint + applyPromptStateReset are
|
|
93
|
+
// duplicated verbatim in src/cli/init/helpers-generator.ts (the embedded
|
|
94
|
+
// gate.cjs fallback used by `flo init` when source helpers can't be located).
|
|
95
|
+
// Any edit to either copy MUST be applied to both — there is no shared module
|
|
96
|
+
// because helpers-generator emits a self-contained string template.
|
|
97
|
+
var NS_LEARNINGS_RE = /\b(remember|recall|insight|lesson learned|gotcha|post.?mortem)\b|we (decid|agree|chose|said)/;
|
|
98
|
+
var NS_TEST_RE = /\b(test|spec|coverage|tested|test case|test cases|tests for|spec for)\b/;
|
|
99
|
+
var NS_EXPLICIT = [
|
|
100
|
+
{ pattern: /\b(pattern|convention|best practice|style|coding rule)\b/, ns: 'patterns', label: 'code patterns and conventions' },
|
|
101
|
+
{ pattern: /\b(code.?map|file structure|project structure|directory)\b/, ns: 'code-map', label: 'codebase navigation' },
|
|
102
|
+
];
|
|
103
|
+
var NS_PATTERN_RES = [/\b(template|example|similar to|how do we|how should)\b/];
|
|
104
|
+
var NS_DOMAIN_RES = [
|
|
105
|
+
/\b(guidance|guide|docs|documentation|rules|how-to)\b/,
|
|
106
|
+
/\b(architecture|design|domain|tenant|migrat|schema|deploy)/,
|
|
107
|
+
/\b(rule|requirement|constraint|compliance)\b/,
|
|
108
|
+
];
|
|
109
|
+
var NS_NAV_RES = [
|
|
110
|
+
/\b(find|where|which file|look up|locate|endpoint|route|url|path)\b/,
|
|
111
|
+
/\b(class|function|method|component|service|entity|module)\b/,
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
function classifyNamespaceHint(promptText) {
|
|
115
|
+
var lower = (promptText || '').toLowerCase();
|
|
116
|
+
if (NS_TEST_RE.test(lower)) return 'Memory namespace hint: use "tests" for test inventory and coverage lookups.';
|
|
117
|
+
if (NS_LEARNINGS_RE.test(lower)) return 'Memory namespace hint: use "learnings" for user-directed decisions and distilled insights.';
|
|
118
|
+
for (var i = 0; i < NS_EXPLICIT.length; i++) {
|
|
119
|
+
if (NS_EXPLICIT[i].pattern.test(lower)) return 'Memory namespace hint: use "' + NS_EXPLICIT[i].ns + '" for ' + NS_EXPLICIT[i].label + '.';
|
|
120
|
+
}
|
|
121
|
+
for (var j = 0; j < NS_DOMAIN_RES.length; j++) {
|
|
122
|
+
if (NS_DOMAIN_RES[j].test(lower)) return 'Memory namespace hint: search "guidance" and "learnings" for domain rules and project decisions.';
|
|
123
|
+
}
|
|
124
|
+
for (var k = 0; k < NS_PATTERN_RES.length; k++) {
|
|
125
|
+
if (NS_PATTERN_RES[k].test(lower)) return 'Memory namespace hint: use "patterns" for code patterns and conventions.';
|
|
126
|
+
}
|
|
127
|
+
for (var m = 0; m < NS_NAV_RES.length; m++) {
|
|
128
|
+
if (NS_NAV_RES[m].test(lower)) return 'Memory namespace hint: use "code-map" for codebase navigation.';
|
|
129
|
+
}
|
|
130
|
+
return '';
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Apply per-prompt state reset shared by `prompt-reminder` (full) and
|
|
134
|
+
// `prompt-state-reset` (defensive safety-net, no emission). Idempotent — both
|
|
135
|
+
// UserPromptSubmit hooks can run it without compounding any field. Caller
|
|
136
|
+
// owns interactionCount and the user-visible REMINDER/Context emissions, so
|
|
137
|
+
// this helper stays silent.
|
|
138
|
+
function applyPromptStateReset(state, promptText) {
|
|
139
|
+
state.memorySearched = false;
|
|
140
|
+
// Wipe per-actor memory tracking too — a new user prompt is a fresh window
|
|
141
|
+
// for both parent AND any subagents the parent may spawn during this turn.
|
|
142
|
+
state.memorySearchedBy = {};
|
|
143
|
+
// learningsStored is session-scoped — once stored, it stays true until session reset.
|
|
144
|
+
// Resetting per-prompt caused false blocks when PR creation was on a later prompt.
|
|
145
|
+
var DIRECTIVE_MAX_LEN = 20;
|
|
146
|
+
var escaped = /^@@\s*/.test(promptText || '');
|
|
147
|
+
state.memoryRequired = !escaped && (promptText || '').length >= 4 && (TASK_RE.test(promptText || '') || (promptText || '').length > DIRECTIVE_MAX_LEN);
|
|
148
|
+
// Stash namespace hint for check-before-agent to emit when Claude actually
|
|
149
|
+
// spawns an Agent (#931). Empty string when nothing matched — overwriting
|
|
150
|
+
// any stale value from the previous prompt.
|
|
151
|
+
state.lastNamespaceHint = classifyNamespaceHint(promptText);
|
|
152
|
+
// Per-actor emission tracking — each subagent's session gets the hint at
|
|
153
|
+
// most once per prompt, but a fresh prompt resets every actor's window so
|
|
154
|
+
// subsequent agents (parent + subagents that spawn their own agents) all
|
|
155
|
+
// see the new classification on their first check-before-agent.
|
|
156
|
+
state.lastNamespaceHintEmittedBy = {};
|
|
157
|
+
}
|
|
86
158
|
// Match npm/yarn/pnpm/bun test, npx vitest|jest|..., bare runners at command-start only,
|
|
87
159
|
// and language-native test commands. The bare-runner arm is anchored so that
|
|
88
160
|
// `npm install jest`, `grep -r vitest src/`, and similar don't false-positive.
|
|
@@ -203,6 +275,11 @@ switch (command) {
|
|
|
203
275
|
// Advisory only — agent spawning is never blocked.
|
|
204
276
|
// Memory-first enforcement happens at the scan/read gate layer.
|
|
205
277
|
// SubagentStart hook injects guidance directive into subagent context.
|
|
278
|
+
//
|
|
279
|
+
// #931 — TaskCreate REMINDER and the namespace hint moved here from
|
|
280
|
+
// prompt-reminder. They only matter when Claude is actually about to spawn
|
|
281
|
+
// an Agent; emitting per-prompt cost ~90 tokens × every prompt × every
|
|
282
|
+
// consumer.
|
|
206
283
|
var s = readState();
|
|
207
284
|
if (config.task_create_first && !s.tasksCreated) {
|
|
208
285
|
process.stdout.write('REMINDER: Use TaskCreate before spawning agents. Task tool is blocked until then.\n');
|
|
@@ -210,6 +287,24 @@ switch (command) {
|
|
|
210
287
|
if (config.memory_first && s.memoryRequired && !s.memorySearched) {
|
|
211
288
|
process.stdout.write('REMINDER: Search memory (mcp__moflo__memory_search) before spawning agents.\n');
|
|
212
289
|
}
|
|
290
|
+
if (s.lastNamespaceHint) {
|
|
291
|
+
// Per-actor single-shot. Each session_id gets the hint at most once per
|
|
292
|
+
// prompt, but the hint itself stays available for other actors (e.g.
|
|
293
|
+
// a subagent that spawns its own agent has its own session_id and is
|
|
294
|
+
// entitled to a fresh emission). Falls back to a `_legacy_` bucket when
|
|
295
|
+
// Claude Code didn't forward a session_id (older host or direct CLI
|
|
296
|
+
// invocation), preserving the old "emit once globally" behavior. The
|
|
297
|
+
// map is wiped by applyPromptStateReset on every new prompt.
|
|
298
|
+
var sid = process.env.HOOK_SESSION_ID || '';
|
|
299
|
+
var emittedBy = s.lastNamespaceHintEmittedBy || {};
|
|
300
|
+
var bucket = sid || '_legacy_';
|
|
301
|
+
if (!emittedBy[bucket]) {
|
|
302
|
+
process.stdout.write(s.lastNamespaceHint + '\n');
|
|
303
|
+
emittedBy[bucket] = true;
|
|
304
|
+
s.lastNamespaceHintEmittedBy = emittedBy;
|
|
305
|
+
writeState(s);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
213
308
|
break;
|
|
214
309
|
}
|
|
215
310
|
case 'check-before-scan': {
|
|
@@ -277,7 +372,8 @@ switch (command) {
|
|
|
277
372
|
break;
|
|
278
373
|
}
|
|
279
374
|
case 'record-skill-run': {
|
|
280
|
-
|
|
375
|
+
var skName = (process.env.TOOL_INPUT_skill || '');
|
|
376
|
+
if (skName === 'simplify' || skName === 'flo-simplify') {
|
|
281
377
|
var s = readState();
|
|
282
378
|
var changed = false;
|
|
283
379
|
if (!s.simplifyRun) { s.simplifyRun = true; changed = true; }
|
|
@@ -346,7 +442,7 @@ switch (command) {
|
|
|
346
442
|
}
|
|
347
443
|
var missing = [];
|
|
348
444
|
if (config.testing_gate && !s.testsRun) missing.push('tests have not run since the last code edit (run npm test, vitest, jest, pytest, or similar)');
|
|
349
|
-
if (config.simplify_gate && !s.simplifyRun) missing.push('/simplify has not run since the last code edit');
|
|
445
|
+
if (config.simplify_gate && !s.simplifyRun) missing.push('/flo-simplify has not run since the last code edit');
|
|
350
446
|
if (config.learnings_gate && !s.learningsStored) missing.push('learnings have not been stored (call mcp__moflo__memory_store)');
|
|
351
447
|
if (missing.length === 0) break;
|
|
352
448
|
process.stderr.write('BLOCKED: gh pr create requires the following before opening a PR:\n');
|
|
@@ -371,20 +467,16 @@ switch (command) {
|
|
|
371
467
|
break;
|
|
372
468
|
}
|
|
373
469
|
case 'prompt-reminder': {
|
|
470
|
+
// Full per-prompt reset. Wired as the first UserPromptSubmit hook (via
|
|
471
|
+
// prompt-hook.mjs). Owns interactionCount + Context warnings; the
|
|
472
|
+
// TaskCreate REMINDER and namespace hint moved to check-before-agent
|
|
473
|
+
// (#931) so they only fire when Claude is actually about to spawn an
|
|
474
|
+
// Agent.
|
|
374
475
|
var s = readState();
|
|
375
|
-
s.memorySearched = false;
|
|
376
|
-
// Wipe per-actor memory tracking too — a new user prompt is a fresh window
|
|
377
|
-
// for both parent AND any subagents the parent may spawn during this turn.
|
|
378
|
-
s.memorySearchedBy = {};
|
|
379
|
-
// learningsStored is session-scoped — once stored, it stays true until session reset.
|
|
380
|
-
// Resetting per-prompt caused false blocks when PR creation was on a later prompt.
|
|
381
476
|
var prompt = process.env.CLAUDE_USER_PROMPT || '';
|
|
382
|
-
|
|
383
|
-
var escaped = /^@@\s*/.test(prompt);
|
|
384
|
-
s.memoryRequired = !escaped && prompt.length >= 4 && (TASK_RE.test(prompt) || prompt.length > DIRECTIVE_MAX_LEN);
|
|
477
|
+
applyPromptStateReset(s, prompt);
|
|
385
478
|
s.interactionCount = (s.interactionCount || 0) + 1;
|
|
386
479
|
writeState(s);
|
|
387
|
-
if (!s.tasksCreated) console.log('REMINDER: Use TaskCreate before spawning agents. Task tool is blocked until then.');
|
|
388
480
|
if (config.context_tracking) {
|
|
389
481
|
var ic = s.interactionCount;
|
|
390
482
|
if (ic > 30) console.log('Context: CRITICAL. Commit, store learnings, suggest new session.');
|
|
@@ -393,12 +485,30 @@ switch (command) {
|
|
|
393
485
|
}
|
|
394
486
|
break;
|
|
395
487
|
}
|
|
488
|
+
case 'prompt-state-reset': {
|
|
489
|
+
// Defensive safety-net hook (#931 dedupe). Wired as the second
|
|
490
|
+
// UserPromptSubmit hook so an exception in prompt-hook.mjs doesn't skip
|
|
491
|
+
// the per-prompt state reset. Idempotent — applyPromptStateReset only
|
|
492
|
+
// sets fields to derived values, and we deliberately do NOT increment
|
|
493
|
+
// interactionCount or emit anything (that's prompt-reminder's job).
|
|
494
|
+
//
|
|
495
|
+
// Skip the disk write on the normal path: prompt-reminder runs first and
|
|
496
|
+
// already wrote the byte-identical post-reset state. Only writeState when
|
|
497
|
+
// the reset actually changed something (i.e., prompt-reminder was skipped
|
|
498
|
+
// because prompt-hook.mjs threw before invoking it).
|
|
499
|
+
var s = readState();
|
|
500
|
+
var prompt = process.env.CLAUDE_USER_PROMPT || '';
|
|
501
|
+
var before = JSON.stringify(s);
|
|
502
|
+
applyPromptStateReset(s, prompt);
|
|
503
|
+
if (JSON.stringify(s) !== before) writeState(s);
|
|
504
|
+
break;
|
|
505
|
+
}
|
|
396
506
|
case 'compact-guidance': {
|
|
397
507
|
console.log('Pre-Compact: Check CLAUDE.md for rules. Use memory search to recover context after compact.');
|
|
398
508
|
break;
|
|
399
509
|
}
|
|
400
510
|
case 'session-reset': {
|
|
401
|
-
writeState({ tasksCreated: false, taskCount: 0, memorySearched: false, memorySearchedBy: {}, memoryRequired: true, learningsStored: false, testsRun: false, simplifyRun: false, interactionCount: 0, sessionStart: new Date().toISOString(), lastBlockedAt: null });
|
|
511
|
+
writeState({ tasksCreated: false, taskCount: 0, memorySearched: false, memorySearchedBy: {}, memoryRequired: true, learningsStored: false, testsRun: false, simplifyRun: false, interactionCount: 0, sessionStart: new Date().toISOString(), lastBlockedAt: null, lastNamespaceHint: '', lastNamespaceHintEmittedBy: {} });
|
|
402
512
|
break;
|
|
403
513
|
}
|
|
404
514
|
default:
|