@ijfw/memory-server 1.3.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -0
- package/fixtures/team/book.json +47 -0
- package/fixtures/team/business.json +47 -0
- package/fixtures/team/content.json +47 -0
- package/fixtures/team/design.json +47 -0
- package/fixtures/team/mixed.json +59 -0
- package/fixtures/team/research.json +47 -0
- package/fixtures/team/software.json +47 -0
- package/package.json +1 -9
- package/src/.registry-meta-key.pem +3 -0
- package/src/active-extension-writer.js +142 -0
- package/src/blackboard.js +360 -0
- package/src/cli-run.js +91 -0
- package/src/codex-agents.js +177 -0
- package/src/compute/extract.js +3 -0
- package/src/compute/fts5.js +4 -4
- package/src/compute/graph-lock.js +0 -2
- package/src/compute/migrations/003-tier-semantic.js +3 -3
- package/src/compute/runner.js +44 -15
- package/src/compute/schema.sql +1 -1
- package/src/cross-orchestrator-cli.js +974 -13
- package/src/cross-orchestrator.js +9 -1
- package/src/dashboard-client.html +353 -1
- package/src/dashboard-server.js +318 -2
- package/src/design-intelligence.js +721 -0
- package/src/dispatch/colon-syntax.js +31 -3
- package/src/dispatch/domain-manifest.js +251 -0
- package/src/dispatch/extension.js +637 -0
- package/src/dispatch/override.js +221 -0
- package/src/dispatch-planner.js +1 -0
- package/src/dream/runner.mjs +3 -3
- package/src/extension-installer.js +1269 -0
- package/src/extension-manifest-schema.js +301 -0
- package/src/extension-permission-check.mjs +79 -0
- package/src/extension-registry.js +619 -0
- package/src/extension-signer.js +905 -0
- package/src/gate-result-formatter.js +95 -0
- package/src/gate-result-schema.js +274 -0
- package/src/gate-result.js +195 -0
- package/src/intent-router.js +2 -0
- package/src/lib/npm-view.js +1 -0
- package/src/memory/fts5.js +3 -3
- package/src/memory/migrations/002-tier-semantic.js +2 -2
- package/src/memory/staleness.js +1 -1
- package/src/memory/tier-promotion.js +6 -6
- package/src/memory/tokenize.js +1 -1
- package/src/memory-feedback.js +372 -0
- package/src/override-manifest-schema.js +146 -0
- package/src/override-resolver.js +699 -0
- package/src/override-use-registry.js +307 -0
- package/src/overrides/presets/academic.md +101 -0
- package/src/overrides/presets/book.md +87 -0
- package/src/overrides/presets/campaign.md +95 -0
- package/src/overrides/presets/screenplay.md +99 -0
- package/src/recovery/checkpoint.js +191 -0
- package/src/redactor.js +2 -0
- package/src/runtime-mediator.js +207 -0
- package/src/sandbox.js +17 -3
- package/src/server.js +94 -2
- package/src/swarm/dispatch-prompt.js +154 -0
- package/src/swarm/planner.js +399 -0
- package/src/swarm/review.js +136 -0
- package/src/swarm/worktree.js +239 -0
- package/src/team/generator.js +119 -0
- package/src/team/schemas.js +341 -0
- package/src/trident/dispatch.js +47 -0
- package/src/update-check.js +1 -1
- package/src/vectors.js +7 -8
package/README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# @ijfw/memory-server
|
|
2
|
+
|
|
3
|
+
IJFW MCP memory server — the runtime backend that powers memory, metrics,
|
|
4
|
+
update checks, and the extension sandbox for all supported AI coding agents.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
This package is installed automatically by `@ijfw/install`. You generally
|
|
9
|
+
do not need to install it manually.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g @ijfw/memory-server
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Extension CLI
|
|
16
|
+
|
|
17
|
+
IJFW ships a full extension system for installing and sandboxing third-party skills.
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Publisher key management
|
|
21
|
+
ijfw extension keygen <author> # Generate an Ed25519 publisher keypair
|
|
22
|
+
ijfw extension trust <keyId> <publicKey> # Add a publisher to your trusted store
|
|
23
|
+
ijfw extension trust-registry [<url>] # Pull + apply the hosted publisher registry
|
|
24
|
+
ijfw extension untrust <keyId> # Remove a publisher from your trusted store
|
|
25
|
+
ijfw extension trusted # List all trusted publishers
|
|
26
|
+
|
|
27
|
+
# Extension lifecycle
|
|
28
|
+
ijfw extension add <source> [flags] # Install an extension (npm name, local path, or https git URL)
|
|
29
|
+
--allow-unsigned # Accept extensions with no signature
|
|
30
|
+
--accept-untrusted # Accept extensions signed by an untrusted publisher (prompts on TTY)
|
|
31
|
+
--activate # Auto-activate after install
|
|
32
|
+
ijfw extension activate <name> # Activate an installed extension (enforces declared permissions)
|
|
33
|
+
ijfw extension deactivate # Deactivate the current extension
|
|
34
|
+
|
|
35
|
+
# Admin / registry maintainer (rare)
|
|
36
|
+
ijfw extension rotate-keys <oldKeyId> <newKeyId> # Produce a signed rotation token
|
|
37
|
+
ijfw extension keygen-meta <author> # Generate the registry meta-keypair
|
|
38
|
+
ijfw extension sign-registry <path> # Sign a registry JSON file in place
|
|
39
|
+
ijfw extension verify-registry <path> # Verify a registry JSON signature
|
|
40
|
+
ijfw extension registry-status # Show registry cache age + signature status
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The rotation flow and registry maintainer docs live in `docs/REGISTRY-MAINTAINER.md`.
|
|
44
|
+
|
|
45
|
+
## MCP Tools
|
|
46
|
+
|
|
47
|
+
| Tool | Description |
|
|
48
|
+
|------|-------------|
|
|
49
|
+
| `ijfw_memory_store` | Store a memory entry |
|
|
50
|
+
| `ijfw_memory_recall` | Recall memory entries |
|
|
51
|
+
| `ijfw_memory_search` | Full-text search over memories |
|
|
52
|
+
| `ijfw_memory_prelude` | Load project context at session start |
|
|
53
|
+
| `ijfw_cross_project_search` | Search memories across projects |
|
|
54
|
+
| `ijfw_metrics` | Read cost + usage metrics |
|
|
55
|
+
| `ijfw_update_check` | Check for IJFW updates |
|
|
56
|
+
| `ijfw_update_apply` | Apply a pending IJFW update |
|
|
57
|
+
| `ijfw_prompt_check` | Validate a prompt against IJFW rules |
|
|
58
|
+
| `ijfw_run` | Run a sandboxed IJFW command |
|
|
59
|
+
|
|
60
|
+
## Build (contributors)
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
cd mcp-server
|
|
64
|
+
npm install
|
|
65
|
+
npm test
|
|
66
|
+
node --experimental-sqlite --test test-*.js
|
|
67
|
+
```
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"charter": {
|
|
3
|
+
"schema_version": "team-charter/v1",
|
|
4
|
+
"team_name": "book-development-team",
|
|
5
|
+
"project_archetypes": ["book"],
|
|
6
|
+
"roles": [
|
|
7
|
+
{
|
|
8
|
+
"name": "chapter-writer",
|
|
9
|
+
"role_type": "book",
|
|
10
|
+
"model": "sonnet",
|
|
11
|
+
"effort": "medium",
|
|
12
|
+
"phase_scope": ["outline", "draft", "revise"],
|
|
13
|
+
"owns": [{"artifact_type": "chapter", "paths": ["manuscript/chapters/**"]}],
|
|
14
|
+
"reviews": [{"artifact_type": "outline", "criteria": ["structure", "continuity"]}],
|
|
15
|
+
"handoff": {"format": "markdown", "required_sections": ["chapter_summary", "open_threads", "changed_artifacts"]},
|
|
16
|
+
"coordination": {"parallel_safe": true, "claim_required": true, "conflicts_with": ["manuscript/chapters/**"]}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"name": "continuity-editor",
|
|
20
|
+
"role_type": "review",
|
|
21
|
+
"model": "sonnet",
|
|
22
|
+
"effort": "medium",
|
|
23
|
+
"phase_scope": ["review", "revise"],
|
|
24
|
+
"owns": [{"artifact_type": "continuity_notes", "paths": ["manuscript/notes/**"]}],
|
|
25
|
+
"reviews": [{"artifact_type": "chapter", "criteria": ["timeline", "voice", "consistency"]}],
|
|
26
|
+
"handoff": {"format": "markdown", "required_sections": ["findings", "continuity_risks"]},
|
|
27
|
+
"coordination": {"parallel_safe": true, "claim_required": true, "conflicts_with": []}
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
"workflow": {
|
|
32
|
+
"schema_version": "team-workflow/v1",
|
|
33
|
+
"project_archetypes": ["book"],
|
|
34
|
+
"artifacts": [
|
|
35
|
+
{"id": "chapter-draft", "type": "chapter", "paths": ["manuscript/chapters/ch01.md"], "owner": "chapter-writer", "reviewers": ["continuity-editor"], "depends_on": [], "verification": ["continuity review"]},
|
|
36
|
+
{"id": "continuity-notes", "type": "continuity_notes", "paths": ["manuscript/notes/continuity.md"], "owner": "continuity-editor", "reviewers": ["chapter-writer"], "depends_on": ["chapter-draft"], "verification": ["open thread audit"]}
|
|
37
|
+
],
|
|
38
|
+
"waves": [
|
|
39
|
+
{"id": "w1", "mode": "parallel", "artifact_ids": ["chapter-draft"]},
|
|
40
|
+
{"id": "w2", "mode": "review", "artifact_ids": ["continuity-notes"]}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"blackboard": {
|
|
44
|
+
"tasks": [{"id": "task-chapter", "title": "Draft chapter one", "status": "ready", "artifact_ids": ["chapter-draft"], "owner": "chapter-writer"}],
|
|
45
|
+
"claims": [{"id": "claim-chapter", "artifact_id": "chapter-draft", "agent": "chapter-writer", "status": "active", "paths": ["manuscript/chapters/ch01.md"]}]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"charter": {
|
|
3
|
+
"schema_version": "team-charter/v1",
|
|
4
|
+
"team_name": "strategy-operations-team",
|
|
5
|
+
"project_archetypes": ["business"],
|
|
6
|
+
"roles": [
|
|
7
|
+
{
|
|
8
|
+
"name": "strategy-lead",
|
|
9
|
+
"role_type": "business",
|
|
10
|
+
"model": "sonnet",
|
|
11
|
+
"effort": "medium",
|
|
12
|
+
"phase_scope": ["diagnose", "plan", "decide"],
|
|
13
|
+
"owns": [{"artifact_type": "strategy_doc", "paths": ["strategy/**"]}],
|
|
14
|
+
"reviews": [{"artifact_type": "risk_register", "criteria": ["assumptions", "decision-quality"]}],
|
|
15
|
+
"handoff": {"format": "markdown", "required_sections": ["recommendation", "assumptions", "tradeoffs"]},
|
|
16
|
+
"coordination": {"parallel_safe": true, "claim_required": true, "conflicts_with": []}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"name": "risk-reviewer",
|
|
20
|
+
"role_type": "review",
|
|
21
|
+
"model": "sonnet",
|
|
22
|
+
"effort": "medium",
|
|
23
|
+
"phase_scope": ["review", "verify"],
|
|
24
|
+
"owns": [{"artifact_type": "risk_register", "paths": ["strategy/risks/**"]}],
|
|
25
|
+
"reviews": [{"artifact_type": "strategy_doc", "criteria": ["feasibility", "downside", "metrics"]}],
|
|
26
|
+
"handoff": {"format": "markdown", "required_sections": ["risks", "mitigations", "decision_points"]},
|
|
27
|
+
"coordination": {"parallel_safe": true, "claim_required": true, "conflicts_with": []}
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
"workflow": {
|
|
32
|
+
"schema_version": "team-workflow/v1",
|
|
33
|
+
"project_archetypes": ["business"],
|
|
34
|
+
"artifacts": [
|
|
35
|
+
{"id": "operating-plan", "type": "strategy_doc", "paths": ["strategy/operating-plan.md"], "owner": "strategy-lead", "reviewers": ["risk-reviewer"], "depends_on": [], "verification": ["decision review"]},
|
|
36
|
+
{"id": "risk-register", "type": "risk_register", "paths": ["strategy/risks/register.md"], "owner": "risk-reviewer", "reviewers": ["strategy-lead"], "depends_on": ["operating-plan"], "verification": ["assumption audit"]}
|
|
37
|
+
],
|
|
38
|
+
"waves": [
|
|
39
|
+
{"id": "w1", "mode": "sequential", "artifact_ids": ["operating-plan"]},
|
|
40
|
+
{"id": "w2", "mode": "review", "artifact_ids": ["risk-register"]}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"blackboard": {
|
|
44
|
+
"tasks": [{"id": "task-plan", "title": "Draft operating plan", "status": "ready", "artifact_ids": ["operating-plan"], "owner": "strategy-lead"}],
|
|
45
|
+
"claims": [{"id": "claim-plan", "artifact_id": "operating-plan", "agent": "strategy-lead", "status": "active", "paths": ["strategy/operating-plan.md"]}]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"charter": {
|
|
3
|
+
"schema_version": "team-charter/v1",
|
|
4
|
+
"team_name": "content-production-team",
|
|
5
|
+
"project_archetypes": ["content"],
|
|
6
|
+
"roles": [
|
|
7
|
+
{
|
|
8
|
+
"name": "content-strategist",
|
|
9
|
+
"role_type": "content",
|
|
10
|
+
"model": "sonnet",
|
|
11
|
+
"effort": "medium",
|
|
12
|
+
"phase_scope": ["plan", "execute"],
|
|
13
|
+
"owns": [{"artifact_type": "brief", "paths": ["content/briefs/**"]}],
|
|
14
|
+
"reviews": [{"artifact_type": "article", "criteria": ["positioning", "brand-voice"]}],
|
|
15
|
+
"handoff": {"format": "markdown", "required_sections": ["message", "audience", "risks"]},
|
|
16
|
+
"coordination": {"parallel_safe": true, "claim_required": true, "conflicts_with": []}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"name": "editor",
|
|
20
|
+
"role_type": "review",
|
|
21
|
+
"model": "sonnet",
|
|
22
|
+
"effort": "medium",
|
|
23
|
+
"phase_scope": ["review", "verify"],
|
|
24
|
+
"owns": [{"artifact_type": "article", "paths": ["content/posts/**"]}],
|
|
25
|
+
"reviews": [{"artifact_type": "brief", "criteria": ["clarity", "seo", "voice"]}],
|
|
26
|
+
"handoff": {"format": "markdown", "required_sections": ["edits", "findings", "publication_status"]},
|
|
27
|
+
"coordination": {"parallel_safe": true, "claim_required": true, "conflicts_with": ["content/posts/**"]}
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
"workflow": {
|
|
32
|
+
"schema_version": "team-workflow/v1",
|
|
33
|
+
"project_archetypes": ["content"],
|
|
34
|
+
"artifacts": [
|
|
35
|
+
{"id": "campaign-brief", "type": "brief", "paths": ["content/briefs/campaign.md"], "owner": "content-strategist", "reviewers": ["editor"], "depends_on": [], "verification": ["brand voice review"]},
|
|
36
|
+
{"id": "article-draft", "type": "article", "paths": ["content/posts/*.mdx"], "owner": "editor", "reviewers": ["content-strategist"], "depends_on": ["campaign-brief"], "verification": ["seo checklist"]}
|
|
37
|
+
],
|
|
38
|
+
"waves": [
|
|
39
|
+
{"id": "w1", "mode": "sequential", "artifact_ids": ["campaign-brief"]},
|
|
40
|
+
{"id": "w2", "mode": "review", "artifact_ids": ["article-draft"]}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"blackboard": {
|
|
44
|
+
"tasks": [{"id": "task-brief", "title": "Prepare campaign brief", "status": "ready", "artifact_ids": ["campaign-brief"], "owner": "content-strategist"}],
|
|
45
|
+
"claims": [{"id": "claim-brief", "artifact_id": "campaign-brief", "agent": "content-strategist", "status": "active", "paths": ["content/briefs/campaign.md"]}]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"charter": {
|
|
3
|
+
"schema_version": "team-charter/v1",
|
|
4
|
+
"team_name": "design-studio-team",
|
|
5
|
+
"project_archetypes": ["design"],
|
|
6
|
+
"roles": [
|
|
7
|
+
{
|
|
8
|
+
"name": "product-designer",
|
|
9
|
+
"role_type": "design",
|
|
10
|
+
"model": "sonnet",
|
|
11
|
+
"effort": "medium",
|
|
12
|
+
"phase_scope": ["discovery", "shape", "execute"],
|
|
13
|
+
"owns": [{"artifact_type": "screen", "paths": ["design/screens/**"]}],
|
|
14
|
+
"reviews": [{"artifact_type": "prototype", "criteria": ["usability", "accessibility"]}],
|
|
15
|
+
"handoff": {"format": "markdown", "required_sections": ["rationale", "changed_artifacts", "open_questions"]},
|
|
16
|
+
"coordination": {"parallel_safe": true, "claim_required": true, "conflicts_with": ["design/tokens/**"]}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"name": "visual-qa",
|
|
20
|
+
"role_type": "review",
|
|
21
|
+
"model": "sonnet",
|
|
22
|
+
"effort": "low",
|
|
23
|
+
"phase_scope": ["review", "verify"],
|
|
24
|
+
"owns": [{"artifact_type": "audit", "paths": ["design/reviews/**"]}],
|
|
25
|
+
"reviews": [{"artifact_type": "screen", "criteria": ["layout", "contrast", "responsive-fit"]}],
|
|
26
|
+
"handoff": {"format": "markdown", "required_sections": ["findings", "severity", "recommendations"]},
|
|
27
|
+
"coordination": {"parallel_safe": true, "claim_required": true, "conflicts_with": []}
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
"workflow": {
|
|
32
|
+
"schema_version": "team-workflow/v1",
|
|
33
|
+
"project_archetypes": ["design"],
|
|
34
|
+
"artifacts": [
|
|
35
|
+
{"id": "screen-system", "type": "screen", "paths": ["design/screens/**"], "owner": "product-designer", "reviewers": ["visual-qa"], "depends_on": [], "verification": ["visual audit"]},
|
|
36
|
+
{"id": "design-review", "type": "audit", "paths": ["design/reviews/**"], "owner": "visual-qa", "reviewers": ["product-designer"], "depends_on": ["screen-system"], "verification": ["accessibility checklist"]}
|
|
37
|
+
],
|
|
38
|
+
"waves": [
|
|
39
|
+
{"id": "w1", "mode": "parallel", "artifact_ids": ["screen-system"]},
|
|
40
|
+
{"id": "w2", "mode": "review", "artifact_ids": ["design-review"]}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"blackboard": {
|
|
44
|
+
"tasks": [{"id": "task-screens", "title": "Draft core screens", "status": "ready", "artifact_ids": ["screen-system"], "owner": "product-designer"}],
|
|
45
|
+
"claims": [{"id": "claim-screens", "artifact_id": "screen-system", "agent": "product-designer", "status": "active", "paths": ["design/screens/**"]}]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"charter": {
|
|
3
|
+
"schema_version": "team-charter/v1",
|
|
4
|
+
"team_name": "mixed-launch-team",
|
|
5
|
+
"project_archetypes": ["software", "design", "content", "mixed"],
|
|
6
|
+
"roles": [
|
|
7
|
+
{
|
|
8
|
+
"name": "app-engineer",
|
|
9
|
+
"role_type": "software",
|
|
10
|
+
"model": "sonnet",
|
|
11
|
+
"effort": "medium",
|
|
12
|
+
"phase_scope": ["execute", "verify"],
|
|
13
|
+
"owns": [{"artifact_type": "app", "paths": ["app/**"]}],
|
|
14
|
+
"reviews": [{"artifact_type": "screen", "criteria": ["integration", "accessibility"]}],
|
|
15
|
+
"handoff": {"format": "markdown", "required_sections": ["changed_artifacts", "tests", "risks"]},
|
|
16
|
+
"coordination": {"parallel_safe": true, "claim_required": true, "conflicts_with": ["app/routes/**"]}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"name": "ux-designer",
|
|
20
|
+
"role_type": "design",
|
|
21
|
+
"model": "sonnet",
|
|
22
|
+
"effort": "medium",
|
|
23
|
+
"phase_scope": ["shape", "review"],
|
|
24
|
+
"owns": [{"artifact_type": "screen", "paths": ["design/**"]}],
|
|
25
|
+
"reviews": [{"artifact_type": "app", "criteria": ["usability", "visual-fit"]}],
|
|
26
|
+
"handoff": {"format": "markdown", "required_sections": ["rationale", "screens", "review_notes"]},
|
|
27
|
+
"coordination": {"parallel_safe": true, "claim_required": true, "conflicts_with": ["design/tokens/**"]}
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "launch-editor",
|
|
31
|
+
"role_type": "content",
|
|
32
|
+
"model": "sonnet",
|
|
33
|
+
"effort": "low",
|
|
34
|
+
"phase_scope": ["execute", "review"],
|
|
35
|
+
"owns": [{"artifact_type": "launch_copy", "paths": ["content/launch/**"]}],
|
|
36
|
+
"reviews": [{"artifact_type": "screen", "criteria": ["message-match", "voice"]}],
|
|
37
|
+
"handoff": {"format": "markdown", "required_sections": ["copy_changes", "voice_notes"]},
|
|
38
|
+
"coordination": {"parallel_safe": true, "claim_required": true, "conflicts_with": []}
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"workflow": {
|
|
43
|
+
"schema_version": "team-workflow/v1",
|
|
44
|
+
"project_archetypes": ["software", "design", "content", "mixed"],
|
|
45
|
+
"artifacts": [
|
|
46
|
+
{"id": "app-shell", "type": "app", "paths": ["app/**"], "owner": "app-engineer", "reviewers": ["ux-designer"], "depends_on": [], "verification": ["npm test"]},
|
|
47
|
+
{"id": "product-screens", "type": "screen", "paths": ["design/**"], "owner": "ux-designer", "reviewers": ["app-engineer", "launch-editor"], "depends_on": [], "verification": ["visual audit"]},
|
|
48
|
+
{"id": "launch-copy", "type": "launch_copy", "paths": ["content/launch/**"], "owner": "launch-editor", "reviewers": ["ux-designer"], "depends_on": ["product-screens"], "verification": ["brand voice review"]}
|
|
49
|
+
],
|
|
50
|
+
"waves": [
|
|
51
|
+
{"id": "w1", "mode": "parallel", "artifact_ids": ["app-shell", "product-screens"]},
|
|
52
|
+
{"id": "w2", "mode": "review", "artifact_ids": ["launch-copy"]}
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
"blackboard": {
|
|
56
|
+
"tasks": [{"id": "task-launch", "title": "Coordinate launch surface", "status": "ready", "artifact_ids": ["app-shell", "product-screens"], "owner": "app-engineer"}],
|
|
57
|
+
"claims": [{"id": "claim-copy", "artifact_id": "launch-copy", "agent": "launch-editor", "status": "active", "paths": ["content/launch/**"]}]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"charter": {
|
|
3
|
+
"schema_version": "team-charter/v1",
|
|
4
|
+
"team_name": "research-synthesis-team",
|
|
5
|
+
"project_archetypes": ["research"],
|
|
6
|
+
"roles": [
|
|
7
|
+
{
|
|
8
|
+
"name": "research-lead",
|
|
9
|
+
"role_type": "research",
|
|
10
|
+
"model": "sonnet",
|
|
11
|
+
"effort": "high",
|
|
12
|
+
"phase_scope": ["question", "collect", "synthesize"],
|
|
13
|
+
"owns": [{"artifact_type": "evidence_table", "paths": ["research/evidence/**"]}],
|
|
14
|
+
"reviews": [{"artifact_type": "synthesis", "criteria": ["method", "source-quality"]}],
|
|
15
|
+
"handoff": {"format": "markdown", "required_sections": ["sources", "findings", "confidence"]},
|
|
16
|
+
"coordination": {"parallel_safe": true, "claim_required": true, "conflicts_with": []}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"name": "method-reviewer",
|
|
20
|
+
"role_type": "review",
|
|
21
|
+
"model": "sonnet",
|
|
22
|
+
"effort": "medium",
|
|
23
|
+
"phase_scope": ["review", "verify"],
|
|
24
|
+
"owns": [{"artifact_type": "method_audit", "paths": ["research/reviews/**"]}],
|
|
25
|
+
"reviews": [{"artifact_type": "evidence_table", "criteria": ["bias", "traceability", "coverage"]}],
|
|
26
|
+
"handoff": {"format": "markdown", "required_sections": ["limitations", "risk", "recommendations"]},
|
|
27
|
+
"coordination": {"parallel_safe": true, "claim_required": true, "conflicts_with": []}
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
"workflow": {
|
|
32
|
+
"schema_version": "team-workflow/v1",
|
|
33
|
+
"project_archetypes": ["research"],
|
|
34
|
+
"artifacts": [
|
|
35
|
+
{"id": "evidence-table", "type": "evidence_table", "paths": ["research/evidence/table.md"], "owner": "research-lead", "reviewers": ["method-reviewer"], "depends_on": [], "verification": ["source audit"]},
|
|
36
|
+
{"id": "method-audit", "type": "method_audit", "paths": ["research/reviews/method.md"], "owner": "method-reviewer", "reviewers": ["research-lead"], "depends_on": ["evidence-table"], "verification": ["methodology review"]}
|
|
37
|
+
],
|
|
38
|
+
"waves": [
|
|
39
|
+
{"id": "w1", "mode": "parallel", "artifact_ids": ["evidence-table"]},
|
|
40
|
+
{"id": "w2", "mode": "review", "artifact_ids": ["method-audit"]}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"blackboard": {
|
|
44
|
+
"tasks": [{"id": "task-evidence", "title": "Build evidence table", "status": "ready", "artifact_ids": ["evidence-table"], "owner": "research-lead"}],
|
|
45
|
+
"claims": [{"id": "claim-evidence", "artifact_id": "evidence-table", "agent": "research-lead", "status": "active", "paths": ["research/evidence/table.md"]}]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"charter": {
|
|
3
|
+
"schema_version": "team-charter/v1",
|
|
4
|
+
"team_name": "software-delivery-team",
|
|
5
|
+
"project_archetypes": ["software"],
|
|
6
|
+
"roles": [
|
|
7
|
+
{
|
|
8
|
+
"name": "implementation-engineer",
|
|
9
|
+
"role_type": "software",
|
|
10
|
+
"model": "sonnet",
|
|
11
|
+
"effort": "medium",
|
|
12
|
+
"phase_scope": ["plan", "execute", "verify"],
|
|
13
|
+
"owns": [{"artifact_type": "module", "paths": ["src/**/*.js"]}],
|
|
14
|
+
"reviews": [{"artifact_type": "test", "criteria": ["coverage", "regression"]}],
|
|
15
|
+
"handoff": {"format": "markdown", "required_sections": ["changed_artifacts", "tests", "risks"]},
|
|
16
|
+
"coordination": {"parallel_safe": true, "claim_required": true, "conflicts_with": ["src/shared/**"]}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"name": "test-reviewer",
|
|
20
|
+
"role_type": "qa",
|
|
21
|
+
"model": "sonnet",
|
|
22
|
+
"effort": "low",
|
|
23
|
+
"phase_scope": ["review", "verify"],
|
|
24
|
+
"owns": [{"artifact_type": "test", "paths": ["test/**/*.js"]}],
|
|
25
|
+
"reviews": [{"artifact_type": "module", "criteria": ["behavior", "edge-cases"]}],
|
|
26
|
+
"handoff": {"format": "markdown", "required_sections": ["findings", "verification"]},
|
|
27
|
+
"coordination": {"parallel_safe": true, "claim_required": true, "conflicts_with": []}
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
"workflow": {
|
|
32
|
+
"schema_version": "team-workflow/v1",
|
|
33
|
+
"project_archetypes": ["software"],
|
|
34
|
+
"artifacts": [
|
|
35
|
+
{"id": "runtime-module", "type": "module", "paths": ["src/**/*.js"], "owner": "implementation-engineer", "reviewers": ["test-reviewer"], "depends_on": [], "verification": ["npm test"]},
|
|
36
|
+
{"id": "regression-tests", "type": "test", "paths": ["test/**/*.js"], "owner": "test-reviewer", "reviewers": ["implementation-engineer"], "depends_on": ["runtime-module"], "verification": ["node --test test/**/*.js"]}
|
|
37
|
+
],
|
|
38
|
+
"waves": [
|
|
39
|
+
{"id": "w1", "mode": "parallel", "artifact_ids": ["runtime-module"]},
|
|
40
|
+
{"id": "w2", "mode": "review", "artifact_ids": ["regression-tests"]}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"blackboard": {
|
|
44
|
+
"tasks": [{"id": "task-runtime", "title": "Implement runtime module", "status": "ready", "artifact_ids": ["runtime-module"], "owner": "implementation-engineer", "depends_on": []}],
|
|
45
|
+
"claims": [{"id": "claim-runtime", "artifact_id": "runtime-module", "agent": "implementation-engineer", "status": "active", "paths": ["src/**/*.js"], "claimed_at": "2026-05-15T00:00:00Z"}]
|
|
46
|
+
}
|
|
47
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ijfw/memory-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "Cross-platform persistent memory server for IJFW. 10 MCP tools (memory + admin/update). Works with 13 MCP-using platforms (Claude Code, Codex, Gemini CLI, Cursor, Windsurf, Copilot, Hermes, Wayland, OpenCode, QwenCode, Cline, KimiCode, OpenClaw) plus Aider via rules-only tier.",
|
|
5
5
|
"author": "Sean Donahoe",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,14 +26,6 @@
|
|
|
26
26
|
"ajv": "^8.12.0",
|
|
27
27
|
"ajv-formats": "^3.0.1"
|
|
28
28
|
},
|
|
29
|
-
"optionalDependencies": {
|
|
30
|
-
"@xenova/transformers": "^2.17.0"
|
|
31
|
-
},
|
|
32
|
-
"peerDependenciesMeta": {
|
|
33
|
-
"@xenova/transformers": {
|
|
34
|
-
"optional": true
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
29
|
"files": [
|
|
38
30
|
"bin/",
|
|
39
31
|
"src/",
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* active-extension-writer.js -- IJFW v1.4.0 W7.1/B2-H-01
|
|
3
|
+
*
|
|
4
|
+
* Writes ~/.ijfw/state/active-extension.json from an extension manifest, and
|
|
5
|
+
* clears it on deactivate. Used by:
|
|
6
|
+
* - `ijfw_run extension:activate <name>` CLI command
|
|
7
|
+
* - installExtension when opts.activate is set
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { readFile, writeFile, unlink, mkdir } from 'node:fs/promises';
|
|
11
|
+
import { join, dirname } from 'node:path';
|
|
12
|
+
import { homedir } from 'node:os';
|
|
13
|
+
import { randomBytes } from 'node:crypto';
|
|
14
|
+
|
|
15
|
+
const STATE_PATH_REL = ['.ijfw', 'state', 'active-extension.json'];
|
|
16
|
+
|
|
17
|
+
function statePath(home) {
|
|
18
|
+
return join(home || homedir(), ...STATE_PATH_REL);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Write the active-extension state file from a manifest + scope.
|
|
23
|
+
* Validates required fields before write. Atomic write via tmp+rename.
|
|
24
|
+
*
|
|
25
|
+
* @param {{ name: string, permissions: { reads: string[], writes: string[] } }} manifest
|
|
26
|
+
* @param {'project'|'org'|'user'} scope
|
|
27
|
+
* @param {{ homeDir?: string }} [opts]
|
|
28
|
+
* @returns {Promise<{ ok: boolean, path?: string, error?: string }>}
|
|
29
|
+
*/
|
|
30
|
+
export async function writeActiveExtension(manifest, scope, opts = {}) {
|
|
31
|
+
if (!manifest || typeof manifest !== 'object') {
|
|
32
|
+
return { ok: false, error: 'manifest must be an object' };
|
|
33
|
+
}
|
|
34
|
+
if (typeof manifest.name !== 'string' || manifest.name.length === 0) {
|
|
35
|
+
return { ok: false, error: 'manifest.name required' };
|
|
36
|
+
}
|
|
37
|
+
if (!['project', 'org', 'user'].includes(scope)) {
|
|
38
|
+
return { ok: false, error: `invalid scope: ${scope}` };
|
|
39
|
+
}
|
|
40
|
+
if (!manifest.permissions || typeof manifest.permissions !== 'object') {
|
|
41
|
+
return { ok: false, error: 'manifest.permissions required' };
|
|
42
|
+
}
|
|
43
|
+
const reads = Array.isArray(manifest.permissions.reads) ? manifest.permissions.reads : [];
|
|
44
|
+
const writes = Array.isArray(manifest.permissions.writes) ? manifest.permissions.writes : [];
|
|
45
|
+
const out = {
|
|
46
|
+
name: manifest.name,
|
|
47
|
+
scope,
|
|
48
|
+
permissions: { reads, writes },
|
|
49
|
+
activated_at: new Date().toISOString(),
|
|
50
|
+
};
|
|
51
|
+
const home = opts && opts.homeDir ? opts.homeDir : (process.env.HOME || homedir());
|
|
52
|
+
const path = statePath(home);
|
|
53
|
+
await mkdir(dirname(path), { recursive: true });
|
|
54
|
+
const tmp = `${path}.tmp.${randomBytes(4).toString('hex')}`;
|
|
55
|
+
await writeFile(tmp, JSON.stringify(out, null, 2) + '\n', 'utf8');
|
|
56
|
+
const { rename } = await import('node:fs/promises');
|
|
57
|
+
await rename(tmp, path);
|
|
58
|
+
return { ok: true, path };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Clear the active-extension state file. Idempotent -- succeeds if file is absent.
|
|
63
|
+
*
|
|
64
|
+
* @param {{ homeDir?: string }} [opts]
|
|
65
|
+
* @returns {Promise<{ ok: boolean, removed: boolean }>}
|
|
66
|
+
*/
|
|
67
|
+
export async function clearActiveExtension(opts = {}) {
|
|
68
|
+
const home = opts && opts.homeDir ? opts.homeDir : (process.env.HOME || homedir());
|
|
69
|
+
try {
|
|
70
|
+
await unlink(statePath(home));
|
|
71
|
+
return { ok: true, removed: true };
|
|
72
|
+
} catch (err) {
|
|
73
|
+
if (err && err.code === 'ENOENT') return { ok: true, removed: false };
|
|
74
|
+
return { ok: false, removed: false };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Read an installed extension's manifest by name. Resolves from project/org/user
|
|
80
|
+
* scope (project first, then org, then user). Used by `extension activate <name>`
|
|
81
|
+
* which doesn't carry the full manifest in args.
|
|
82
|
+
*
|
|
83
|
+
* Scope paths (matching the rest of the codebase):
|
|
84
|
+
* project: <projectRoot>/.ijfw/extensions/<name>/manifest.json
|
|
85
|
+
* org: ~/.ijfw/extensions-org/<name>/manifest.json
|
|
86
|
+
* user: ~/.ijfw/extensions-user/<name>/manifest.json
|
|
87
|
+
*
|
|
88
|
+
* @param {string} name
|
|
89
|
+
* @param {string} [projectRoot]
|
|
90
|
+
* @param {{ homeDir?: string, strictShadow?: boolean }} [opts]
|
|
91
|
+
* @returns {Promise<{ ok: boolean, manifest?: object, scope?: string, path?: string, error?: string }>}
|
|
92
|
+
*/
|
|
93
|
+
export async function findInstalledManifest(name, projectRoot, opts = {}) {
|
|
94
|
+
// eslint-disable-next-line security/detect-unsafe-regex -- anchored, bounded npm name shape; no nested ambiguous repetition
|
|
95
|
+
if (typeof name !== 'string' || !/^(@[a-z0-9-]+\/)?[a-z][a-z0-9-]*$/.test(name)) {
|
|
96
|
+
return { ok: false, error: 'invalid extension name' };
|
|
97
|
+
}
|
|
98
|
+
const home = opts && opts.homeDir ? opts.homeDir : (process.env.HOME || homedir());
|
|
99
|
+
const candidates = [];
|
|
100
|
+
if (projectRoot) {
|
|
101
|
+
candidates.push({ scope: 'project', path: join(projectRoot, '.ijfw', 'extensions', name, 'manifest.json') });
|
|
102
|
+
}
|
|
103
|
+
candidates.push({ scope: 'org', path: join(home, '.ijfw', 'extensions-org', name, 'manifest.json') });
|
|
104
|
+
candidates.push({ scope: 'user', path: join(home, '.ijfw', 'extensions-user', name, 'manifest.json') });
|
|
105
|
+
|
|
106
|
+
// Collect all found manifests to detect project-scope shadowing.
|
|
107
|
+
const found = [];
|
|
108
|
+
for (const c of candidates) {
|
|
109
|
+
try {
|
|
110
|
+
const raw = await readFile(c.path, 'utf8');
|
|
111
|
+
const manifest = JSON.parse(raw);
|
|
112
|
+
found.push({ scope: c.scope, path: c.path, manifest });
|
|
113
|
+
} catch (err) {
|
|
114
|
+
if (err && err.code === 'ENOENT') continue;
|
|
115
|
+
if (err instanceof SyntaxError) continue;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (found.length === 0) {
|
|
120
|
+
return { ok: false, error: `extension "${name}" not found in project/org/user scope` };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const winner = found[0];
|
|
124
|
+
|
|
125
|
+
// B13.1: warn when project-scope shadows a lower-priority scope entry.
|
|
126
|
+
if (winner.scope === 'project' && found.length > 1) {
|
|
127
|
+
const shadowed = found[1];
|
|
128
|
+
const winnerKeyId = winner.manifest.signature?.keyId ?? '(unsigned)';
|
|
129
|
+
const shadowedKeyId = shadowed.manifest.signature?.keyId ?? '(unsigned)';
|
|
130
|
+
if (opts && opts.strictShadow) {
|
|
131
|
+
return {
|
|
132
|
+
ok: false,
|
|
133
|
+
error: `extension activate: project-scope "${name}" shadows ${shadowed.scope}-scope "${name}" (keyId ${winnerKeyId} vs ${shadowedKeyId}) — refused by strictShadow`,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
process.stderr.write(
|
|
137
|
+
`[ijfw] extension activate: project-scope "${name}" shadows ${shadowed.scope}-scope "${name}" (keyId ${winnerKeyId} vs ${shadowedKeyId}) — using project\n`,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return { ok: true, manifest: winner.manifest, scope: winner.scope, path: winner.path };
|
|
142
|
+
}
|