iranti 0.2.51 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -17
- package/dist/scripts/api-key-create.js +1 -1
- package/dist/scripts/api-key-list.js +1 -1
- package/dist/scripts/api-key-revoke.js +1 -1
- package/dist/scripts/claude-code-memory-hook.js +116 -30
- package/dist/scripts/codex-setup.js +86 -4
- package/dist/scripts/iranti-cli.js +1359 -57
- package/dist/scripts/iranti-mcp.js +578 -75
- package/dist/scripts/seed.js +11 -6
- package/dist/scripts/setup.js +1 -1
- package/dist/src/api/healthChecks.d.ts +29 -0
- package/dist/src/api/healthChecks.d.ts.map +1 -0
- package/dist/src/api/healthChecks.js +72 -0
- package/dist/src/api/healthChecks.js.map +1 -0
- package/dist/src/api/middleware/validation.d.ts +22 -0
- package/dist/src/api/middleware/validation.d.ts.map +1 -1
- package/dist/src/api/middleware/validation.js +93 -3
- package/dist/src/api/middleware/validation.js.map +1 -1
- package/dist/src/api/routes/knowledge.d.ts.map +1 -1
- package/dist/src/api/routes/knowledge.js +53 -0
- package/dist/src/api/routes/knowledge.js.map +1 -1
- package/dist/src/api/routes/memory.d.ts.map +1 -1
- package/dist/src/api/routes/memory.js +73 -9
- package/dist/src/api/routes/memory.js.map +1 -1
- package/dist/src/api/server.js +38 -43
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/attendant/AttendantInstance.d.ts +135 -2
- package/dist/src/attendant/AttendantInstance.d.ts.map +1 -1
- package/dist/src/attendant/AttendantInstance.js +1836 -93
- package/dist/src/attendant/AttendantInstance.js.map +1 -1
- package/dist/src/attendant/index.d.ts +1 -1
- package/dist/src/attendant/index.d.ts.map +1 -1
- package/dist/src/attendant/index.js +1 -1
- package/dist/src/attendant/index.js.map +1 -1
- package/dist/src/attendant/registry.d.ts.map +1 -1
- package/dist/src/attendant/registry.js +2 -0
- package/dist/src/attendant/registry.js.map +1 -1
- package/dist/src/chat/index.d.ts +23 -0
- package/dist/src/chat/index.d.ts.map +1 -1
- package/dist/src/chat/index.js +111 -22
- package/dist/src/chat/index.js.map +1 -1
- package/dist/src/generated/prisma/browser.d.ts +5 -0
- package/dist/src/generated/prisma/browser.d.ts.map +1 -1
- package/dist/src/generated/prisma/client.d.ts +5 -0
- package/dist/src/generated/prisma/client.d.ts.map +1 -1
- package/dist/src/generated/prisma/commonInputTypes.d.ts +48 -0
- package/dist/src/generated/prisma/commonInputTypes.d.ts.map +1 -1
- package/dist/src/generated/prisma/internal/class.d.ts +11 -0
- package/dist/src/generated/prisma/internal/class.d.ts.map +1 -1
- package/dist/src/generated/prisma/internal/class.js +4 -4
- package/dist/src/generated/prisma/internal/class.js.map +1 -1
- package/dist/src/generated/prisma/internal/prismaNamespace.d.ts +92 -1
- package/dist/src/generated/prisma/internal/prismaNamespace.d.ts.map +1 -1
- package/dist/src/generated/prisma/internal/prismaNamespace.js +17 -2
- package/dist/src/generated/prisma/internal/prismaNamespace.js.map +1 -1
- package/dist/src/generated/prisma/internal/prismaNamespaceBrowser.d.ts +16 -0
- package/dist/src/generated/prisma/internal/prismaNamespaceBrowser.d.ts.map +1 -1
- package/dist/src/generated/prisma/internal/prismaNamespaceBrowser.js +17 -2
- package/dist/src/generated/prisma/internal/prismaNamespaceBrowser.js.map +1 -1
- package/dist/src/generated/prisma/models/StaffEvent.d.ts +1184 -0
- package/dist/src/generated/prisma/models/StaffEvent.d.ts.map +1 -0
- package/dist/src/generated/prisma/models/StaffEvent.js +3 -0
- package/dist/src/generated/prisma/models/StaffEvent.js.map +1 -0
- package/dist/src/generated/prisma/models.d.ts +1 -0
- package/dist/src/generated/prisma/models.d.ts.map +1 -1
- package/dist/src/lib/assistantCheckpoint.d.ts +21 -0
- package/dist/src/lib/assistantCheckpoint.d.ts.map +1 -0
- package/dist/src/lib/assistantCheckpoint.js +143 -0
- package/dist/src/lib/assistantCheckpoint.js.map +1 -0
- package/dist/src/lib/autoRemember.d.ts +15 -0
- package/dist/src/lib/autoRemember.d.ts.map +1 -1
- package/dist/src/lib/autoRemember.js +433 -71
- package/dist/src/lib/autoRemember.js.map +1 -1
- package/dist/src/lib/cliHelpCatalog.d.ts.map +1 -1
- package/dist/src/lib/cliHelpCatalog.js +23 -11
- package/dist/src/lib/cliHelpCatalog.js.map +1 -1
- package/dist/src/lib/cliHelpRenderer.d.ts +1 -0
- package/dist/src/lib/cliHelpRenderer.d.ts.map +1 -1
- package/dist/src/lib/cliHelpRenderer.js +4 -0
- package/dist/src/lib/cliHelpRenderer.js.map +1 -1
- package/dist/src/lib/commandErrors.d.ts +5 -1
- package/dist/src/lib/commandErrors.d.ts.map +1 -1
- package/dist/src/lib/commandErrors.js +250 -17
- package/dist/src/lib/commandErrors.js.map +1 -1
- package/dist/src/lib/createFirstPartyIranti.d.ts.map +1 -1
- package/dist/src/lib/createFirstPartyIranti.js +1 -0
- package/dist/src/lib/createFirstPartyIranti.js.map +1 -1
- package/dist/src/lib/dbStaffEventEmitter.d.ts +2 -0
- package/dist/src/lib/dbStaffEventEmitter.d.ts.map +1 -1
- package/dist/src/lib/dbStaffEventEmitter.js +15 -0
- package/dist/src/lib/dbStaffEventEmitter.js.map +1 -1
- package/dist/src/lib/hostMemoryFormatting.d.ts +25 -0
- package/dist/src/lib/hostMemoryFormatting.d.ts.map +1 -0
- package/dist/src/lib/hostMemoryFormatting.js +55 -0
- package/dist/src/lib/hostMemoryFormatting.js.map +1 -0
- package/dist/src/lib/issueFacts.d.ts +37 -0
- package/dist/src/lib/issueFacts.d.ts.map +1 -0
- package/dist/src/lib/issueFacts.js +72 -0
- package/dist/src/lib/issueFacts.js.map +1 -0
- package/dist/src/lib/llm.d.ts +8 -0
- package/dist/src/lib/llm.d.ts.map +1 -1
- package/dist/src/lib/llm.js +33 -0
- package/dist/src/lib/llm.js.map +1 -1
- package/dist/src/lib/packageRoot.d.ts +2 -0
- package/dist/src/lib/packageRoot.d.ts.map +1 -0
- package/dist/src/lib/packageRoot.js +22 -0
- package/dist/src/lib/packageRoot.js.map +1 -0
- package/dist/src/lib/projectLearning.d.ts +21 -0
- package/dist/src/lib/projectLearning.d.ts.map +1 -0
- package/dist/src/lib/projectLearning.js +357 -0
- package/dist/src/lib/projectLearning.js.map +1 -0
- package/dist/src/lib/protocolEnforcement.d.ts +29 -0
- package/dist/src/lib/protocolEnforcement.d.ts.map +1 -0
- package/dist/src/lib/protocolEnforcement.js +124 -0
- package/dist/src/lib/protocolEnforcement.js.map +1 -0
- package/dist/src/lib/providers/claude.js +1 -1
- package/dist/src/lib/providers/claude.js.map +1 -1
- package/dist/src/lib/router.js +1 -1
- package/dist/src/lib/router.js.map +1 -1
- package/dist/src/lib/runtimeEnv.d.ts.map +1 -1
- package/dist/src/lib/runtimeEnv.js +8 -3
- package/dist/src/lib/runtimeEnv.js.map +1 -1
- package/dist/src/lib/scaffoldCloseout.d.ts +27 -0
- package/dist/src/lib/scaffoldCloseout.d.ts.map +1 -0
- package/dist/src/lib/scaffoldCloseout.js +139 -0
- package/dist/src/lib/scaffoldCloseout.js.map +1 -0
- package/dist/src/lib/semanticFactTags.d.ts +10 -0
- package/dist/src/lib/semanticFactTags.d.ts.map +1 -0
- package/dist/src/lib/semanticFactTags.js +166 -0
- package/dist/src/lib/semanticFactTags.js.map +1 -0
- package/dist/src/lib/sessionLedger.d.ts +94 -0
- package/dist/src/lib/sessionLedger.d.ts.map +1 -0
- package/dist/src/lib/sessionLedger.js +997 -0
- package/dist/src/lib/sessionLedger.js.map +1 -0
- package/dist/src/lib/sharedStateInvalidation.d.ts +10 -0
- package/dist/src/lib/sharedStateInvalidation.d.ts.map +1 -0
- package/dist/src/lib/sharedStateInvalidation.js +184 -0
- package/dist/src/lib/sharedStateInvalidation.js.map +1 -0
- package/dist/src/lib/staffEventsTable.d.ts +3 -0
- package/dist/src/lib/staffEventsTable.d.ts.map +1 -0
- package/dist/src/lib/staffEventsTable.js +58 -0
- package/dist/src/lib/staffEventsTable.js.map +1 -0
- package/dist/src/librarian/index.d.ts.map +1 -1
- package/dist/src/librarian/index.js +113 -2
- package/dist/src/librarian/index.js.map +1 -1
- package/dist/src/library/client.d.ts +6 -1
- package/dist/src/library/client.d.ts.map +1 -1
- package/dist/src/library/client.js +21 -7
- package/dist/src/library/client.js.map +1 -1
- package/dist/src/library/embeddings.d.ts +9 -1
- package/dist/src/library/embeddings.d.ts.map +1 -1
- package/dist/src/library/embeddings.js +28 -3
- package/dist/src/library/embeddings.js.map +1 -1
- package/dist/src/library/queries.d.ts.map +1 -1
- package/dist/src/library/queries.js +263 -46
- package/dist/src/library/queries.js.map +1 -1
- package/dist/src/sdk/index.d.ts +52 -1
- package/dist/src/sdk/index.d.ts.map +1 -1
- package/dist/src/sdk/index.js +546 -98
- package/dist/src/sdk/index.js.map +1 -1
- package/package.json +24 -3
- package/prisma/migrations/20260331101500_add_staff_events_ledger/migration.sql +24 -0
- package/prisma/schema.prisma +22 -0
package/README.md
CHANGED
|
@@ -9,10 +9,11 @@
|
|
|
9
9
|
|
|
10
10
|
Iranti gives agents persistent, identity-based memory. Facts written by one agent are retrievable by any other agent through exact entity+key lookup. Iranti also supports hybrid search (lexical + vector) when exact keys are unknown. Memory persists across sessions and survives context window limits.
|
|
11
11
|
|
|
12
|
-
**
|
|
12
|
+
**Repo version:** `0.3.0`
|
|
13
13
|
Published packages:
|
|
14
|
-
- `iranti@0.
|
|
15
|
-
- `@iranti/sdk@0.
|
|
14
|
+
- npm `iranti@0.3.0`
|
|
15
|
+
- npm `@iranti/sdk@0.3.0`
|
|
16
|
+
- PyPI `iranti==0.3.0`
|
|
16
17
|
|
|
17
18
|
---
|
|
18
19
|
|
|
@@ -52,25 +53,29 @@ Vector databases answer "what's similar to X?" Iranti answers "what do we know a
|
|
|
52
53
|
|
|
53
54
|
## Benchmark Summary
|
|
54
55
|
|
|
55
|
-
Iranti has
|
|
56
|
+
Iranti now has current rerun evidence across exact retrieval, process continuity, upgrade durability, relationships, bounded conflict handling, and bounded recovery behavior. The current picture is stronger and narrower than the early validation story: exact, durable, shared memory is validated; broad semantic-memory and autonomous-recovery claims still need explicit limits.
|
|
56
57
|
|
|
57
58
|
### Confirmed Strengths
|
|
58
59
|
|
|
59
|
-
- **Exact lookup (`iranti_query`)**:
|
|
60
|
-
- **Persistence across sessions**: Facts survive context-window loss and genuine process boundaries
|
|
60
|
+
- **Exact lookup (`iranti_query`)**: The prepublish candidate for the current `0.3.0` line still scored `10/10` on the canonical B1 exact-retrieval arm.
|
|
61
|
+
- **Persistence across sessions and processes**: Facts survive context-window loss and genuine process boundaries, with current reruns and validation passes covering process-isolated reads plus cross-process invalidation.
|
|
62
|
+
- **Upgrade durability**: A fresh continuity chain now passes across public npm `0.2.49 -> 0.2.50 -> 0.2.51` plus a final prepublish candidate hop on the `0.3.0` line.
|
|
61
63
|
- **Conflict handling**: Reliable when confidence differentials are large and explicit.
|
|
62
|
-
- **
|
|
64
|
+
- **Relationship traversal and multi-agent coordination**: Relationship writes plus one-hop/deep traversal work, and agents can share memory across genuine subprocess boundaries with zero shared conversational context.
|
|
63
65
|
- **Provenance on writes**: Write-side attribution through stored source metadata is working and benchmark-confirmed.
|
|
64
|
-
- **Ingest**: Prose extraction is accurate on clean entities in
|
|
65
|
-
- **Observe with hints**: `iranti_observe`
|
|
66
|
-
- **
|
|
66
|
+
- **Ingest**: Prose extraction is accurate on clean entities in the bounded rerun surfaces already documented.
|
|
67
|
+
- **Observe with hints / explicit recovery**: `iranti_observe` with hints and explicit query-based recovery are meaningfully useful today.
|
|
68
|
+
- **Protocol enforcement turn-gate**: Strict turn-cycle enforcement (handshake → attend → discover → post-response) is validated by focused route and MCP regression tests. In `strict` mode, KB discovery routes return HTTP 428 with a structured violation payload before an agent that skipped attend can silently read stale memory. Injected facts now include a `lastUpdated` timestamp so the calling agent can judge freshness at the point of injection.
|
|
69
|
+
|
|
70
|
+
Recent fixes since the last rerun:
|
|
71
|
+
- **Search now bridges semantic hits across relationships for filtered retrieval.** A strong incident or issue hit can now propagate back onto the owning filtered entity over up to two hops, so filtered project search no longer depends on direct lexical overlap alone.
|
|
72
|
+
- **`iranti_attend` now safe-defaults parse failures toward memory on non-greeting turns.** Terse prompts such as `help`, `why?`, or `how?` no longer silently fall through to `classification_parse_failed_default_false`.
|
|
73
|
+
- **Hybrid search now indexes entity addresses directly.** Addressed queries such as `project/<id> status` no longer rely on value-summary overlap alone.
|
|
67
74
|
|
|
68
75
|
### Current Limits
|
|
69
76
|
|
|
70
|
-
- **
|
|
71
|
-
-
|
|
72
|
-
- **Observe performs better with explicit entity hints than with cold-start discovery.**
|
|
73
|
-
- **Upgrade durability should be scoped carefully.** The `v0.2.21` upgrade procedure reinitialized the instance under test; do not assume KB data survives upgrades without an explicit preservation or migration path.
|
|
77
|
+
- **Upgrade durability is now test-covered.** The `v0.2.21` upgrade reinitialized the instance under test — a one-time operator incident, not a systemic design flaw. All Prisma migrations are additive (no DROP or TRUNCATE); Staff Namespace seeding is guarded by `isSeeded()`; `seed-codebase.ts` upserts to `codebase/*` entities only. A KB preservation test in `tests/runtime-lifecycle/run_setup_upgrade_tests.ts` now confirms user KB data written before a `setup` re-run survives intact.
|
|
78
|
+
- **Project learning is now only a bounded bind-time snapshot.** When you bind a project, Iranti derives a stable `IRANTI_CODEBASE_ENTITY` and writes a small snapshot from authoritative files such as `package.json`, `README.md`, `tsconfig.json`, `pyproject.toml`, `prisma/schema.prisma`, and common source directories. It does not yet crawl the repo continuously or build autonomous whole-project understanding.
|
|
74
79
|
- **Relationship and provenance reflection surfaces remain partially permission-gated in benchmark sessions.** The rerun did not prove `iranti_relate`, `iranti_related`, `iranti_related_deep`, or `iranti_who_knows` end-to-end under the benchmark session policy.
|
|
75
80
|
|
|
76
81
|
### Practical Position
|
|
@@ -78,9 +83,10 @@ Iranti has now been rerun against a broader benchmark program covering 11 active
|
|
|
78
83
|
Iranti is strongest today as **structured memory infrastructure for multi-agent systems**:
|
|
79
84
|
- exact entity/key lookup
|
|
80
85
|
- durable shared memory
|
|
81
|
-
- provenance-aware writes
|
|
86
|
+
- provenance-aware writes with source attribution and freshness timestamps
|
|
82
87
|
- conflict-aware storage
|
|
83
88
|
- session-aware recovery
|
|
89
|
+
- protocol-enforced turn discipline for trustworthy injection (opt-in strict mode)
|
|
84
90
|
|
|
85
91
|
It should not yet be described as a fully general semantic-memory, semantic-search, or autonomous-memory-injection system.
|
|
86
92
|
|
|
@@ -465,6 +471,7 @@ iranti project init . --instance local --agent-id chatbot_main
|
|
|
465
471
|
```
|
|
466
472
|
|
|
467
473
|
This writes `.env.iranti` in the project with the correct `IRANTI_URL`, `IRANTI_API_KEY`, and default agent identity.
|
|
474
|
+
It also writes a derived `IRANTI_CODEBASE_ENTITY` and a bounded initial project snapshot for that bound repo.
|
|
468
475
|
|
|
469
476
|
Later changes use the same surface:
|
|
470
477
|
|
|
@@ -607,13 +614,16 @@ for item in matches:
|
|
|
607
614
|
|
|
608
615
|
### Context Persistence (attend)
|
|
609
616
|
|
|
617
|
+
`handshake()` establishes the session contract. Discovery surfaces such as `query`, `search`, `get_related`, and `who_knows` are now fail-closed until the host has run `handshake()` for the session and `attend()` for the current turn. Starting a new `attend(phase="pre-response")` turn without first closing the previous one with `attend(phase="post-response")` is now blocked as a protocol violation, and `inspectSession()` / `listSessions()` expose structured lifecycle compliance state (`healthy`, `degraded`, `non_compliant`) so hosts and operators can see when breadcrumb discipline is slipping.
|
|
618
|
+
|
|
610
619
|
```python
|
|
611
620
|
# Before each LLM call, let Attendant decide if memory is needed
|
|
612
621
|
result = client.attend(
|
|
613
622
|
agent_id="research_agent_001",
|
|
614
623
|
latest_message="What's Jane Smith's current affiliation?",
|
|
615
624
|
current_context="User: What's Jane Smith's current affiliation?\nAssistant: Let me check...",
|
|
616
|
-
max_facts=5
|
|
625
|
+
max_facts=5,
|
|
626
|
+
phase="pre-response"
|
|
617
627
|
)
|
|
618
628
|
|
|
619
629
|
if result["shouldInject"]:
|
|
@@ -729,6 +739,7 @@ middleware.after_receive(
|
|
|
729
739
|
1. `before_send()` calls `attend()` with conversation context
|
|
730
740
|
2. Forgotten facts are prepended as `[MEMORY: ...]`
|
|
731
741
|
3. `after_receive()` extracts new facts and saves them (best-effort)
|
|
742
|
+
4. If the host skips `handshake()` or `attend()`, discovery calls block instead of returning warn-only metadata
|
|
732
743
|
|
|
733
744
|
**Note**: Browser extensions are blocked by ChatGPT and Claude's Content Security Policy. Use API-based middleware instead.
|
|
734
745
|
|
|
@@ -757,9 +768,10 @@ Express server on port 3001 with endpoints:
|
|
|
757
768
|
- `GET /kb/query/:entityType/:entityId/:key` - Query specific fact
|
|
758
769
|
- `GET /kb/query/:entityType/:entityId` - Query all facts for entity
|
|
759
770
|
- `GET /kb/search` - Hybrid search across facts
|
|
760
|
-
- `POST /memory/attend` - Decide whether to inject memory for this turn
|
|
771
|
+
- `POST /memory/attend` - Decide whether to inject memory for this turn and unlock one discovery step for the current turn
|
|
761
772
|
- `POST /memory/observe` - Context persistence (inject missing facts)
|
|
762
773
|
- `POST /memory/handshake` - Working memory brief for agent session
|
|
774
|
+
- `GET /memory/ledger` - Read structured session ledger events from `staff_events`
|
|
763
775
|
- `GET /memory/sessions` - List persisted operator-visible session checkpoints across agents, with optional operator filters/sorting
|
|
764
776
|
- `GET /memory/session/:agentId` - Inspect the current persisted session checkpoint/recovery state
|
|
765
777
|
- `POST /kb/relate` - Create entity relationship
|
|
@@ -767,6 +779,7 @@ Express server on port 3001 with endpoints:
|
|
|
767
779
|
- `POST /agents/register` - Register agent in registry
|
|
768
780
|
|
|
769
781
|
All endpoints require `X-Iranti-Key` header for authentication.
|
|
782
|
+
Discovery endpoints return `428 Precondition Required` when a host skips the required session `handshake` or current-turn `attend`.
|
|
770
783
|
|
|
771
784
|
---
|
|
772
785
|
|
|
@@ -27,7 +27,7 @@ async function main() {
|
|
|
27
27
|
console.error('DATABASE_URL is required.');
|
|
28
28
|
process.exit(1);
|
|
29
29
|
}
|
|
30
|
-
(0, client_1.initDb)(dbUrl);
|
|
30
|
+
(0, client_1.initDb)(dbUrl, { applicationName: 'iranti:script:api_key_create' });
|
|
31
31
|
const created = await (0, apiKeys_1.createOrRotateApiKey)({
|
|
32
32
|
keyId,
|
|
33
33
|
owner,
|
|
@@ -9,7 +9,7 @@ async function main() {
|
|
|
9
9
|
console.error('DATABASE_URL is required.');
|
|
10
10
|
process.exit(1);
|
|
11
11
|
}
|
|
12
|
-
(0, client_1.initDb)(dbUrl);
|
|
12
|
+
(0, client_1.initDb)(dbUrl, { applicationName: 'iranti:script:api_key_list' });
|
|
13
13
|
const keys = await (0, apiKeys_1.listApiKeys)();
|
|
14
14
|
if (keys.length === 0) {
|
|
15
15
|
console.log('No registry API keys found.');
|
|
@@ -20,7 +20,7 @@ async function main() {
|
|
|
20
20
|
console.error('DATABASE_URL is required.');
|
|
21
21
|
process.exit(1);
|
|
22
22
|
}
|
|
23
|
-
(0, client_1.initDb)(dbUrl);
|
|
23
|
+
(0, client_1.initDb)(dbUrl, { applicationName: 'iranti:script:api_key_revoke' });
|
|
24
24
|
const revoked = await (0, apiKeys_1.revokeApiKey)(keyId);
|
|
25
25
|
if (!revoked) {
|
|
26
26
|
console.error(`API key not found: ${keyId}`);
|
|
@@ -9,7 +9,10 @@ const path_1 = __importDefault(require("path"));
|
|
|
9
9
|
const createFirstPartyIranti_1 = require("../src/lib/createFirstPartyIranti");
|
|
10
10
|
const runtimeEnv_1 = require("../src/lib/runtimeEnv");
|
|
11
11
|
const staffEventRegistry_1 = require("../src/lib/staffEventRegistry");
|
|
12
|
+
const client_1 = require("../src/library/client");
|
|
12
13
|
const autoRemember_1 = require("../src/lib/autoRemember");
|
|
14
|
+
const assistantCheckpoint_1 = require("../src/lib/assistantCheckpoint");
|
|
15
|
+
const hostMemoryFormatting_1 = require("../src/lib/hostMemoryFormatting");
|
|
13
16
|
const MEMORY_NEED_POSITIVE_PATTERNS = [
|
|
14
17
|
/\bwhat(?:'s| is| was)?\s+my\b/i,
|
|
15
18
|
/\bdo you remember\b/i,
|
|
@@ -40,7 +43,7 @@ function printHelp() {
|
|
|
40
43
|
'',
|
|
41
44
|
'Reads Claude Code hook JSON from stdin and returns hookSpecificOutput.additionalContext on stdout.',
|
|
42
45
|
'This helper retrieves working memory; durable KB writes still require explicit iranti_write/ingest calls.',
|
|
43
|
-
'Set IRANTI_AUTO_REMEMBER=true to auto-save
|
|
46
|
+
'Set IRANTI_AUTO_REMEMBER=true to auto-save prompt-side personal/project facts. Assistant-response continuity facts and shared checkpoints are captured on Stop regardless.',
|
|
44
47
|
].join('\n'));
|
|
45
48
|
}
|
|
46
49
|
function parseArgs(argv) {
|
|
@@ -228,19 +231,39 @@ function getMaxFacts() {
|
|
|
228
231
|
return Math.min(12, Math.trunc(raw));
|
|
229
232
|
}
|
|
230
233
|
function formatSessionContext(facts, cwd) {
|
|
231
|
-
const limited = facts.slice(0, getMaxFacts())
|
|
234
|
+
const limited = (0, hostMemoryFormatting_1.assignStructuredFactIds)(facts.slice(0, getMaxFacts()).map((fact) => ({
|
|
235
|
+
...fact,
|
|
236
|
+
entityKey: `${fact.entity}/${fact.key}`,
|
|
237
|
+
})));
|
|
232
238
|
const lines = [
|
|
233
239
|
'[Iranti Session Memory]',
|
|
234
240
|
`Project: ${path_1.default.basename(cwd)}`,
|
|
241
|
+
'REQUIRED: Call mcp__iranti__iranti_handshake before responding to the first user message.',
|
|
242
|
+
'REQUIRED: Call mcp__iranti__iranti_attend(phase=\'pre-response\') before every reply and before factual discovery.',
|
|
243
|
+
'REQUIRED: After every response, call mcp__iranti__iranti_attend(phase=\'post-response\').',
|
|
244
|
+
'REQUIRED: Prefer injected Iranti facts before re-inferring project state.',
|
|
235
245
|
];
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
246
|
+
const block = (0, hostMemoryFormatting_1.formatStructuredFactBlock)(limited, {
|
|
247
|
+
title: 'Iranti Session Facts',
|
|
248
|
+
introLines: [
|
|
249
|
+
'Use these loaded facts as the starting working-memory frame for this session.',
|
|
250
|
+
'Prefer them before re-inferring project state.',
|
|
251
|
+
'Fact IDs are stable only within this block.',
|
|
252
|
+
],
|
|
253
|
+
});
|
|
254
|
+
if (block)
|
|
255
|
+
lines.push(block);
|
|
242
256
|
return lines.join('\n');
|
|
243
257
|
}
|
|
258
|
+
function formatPreCompactContext() {
|
|
259
|
+
return [
|
|
260
|
+
'[Iranti Post-Compaction Recovery]',
|
|
261
|
+
'Context was just compacted. BEFORE responding to the next user message:',
|
|
262
|
+
'1. Call mcp__iranti__iranti_handshake with the current task to restore working memory.',
|
|
263
|
+
'2. Do not respond until the handshake completes.',
|
|
264
|
+
'REQUIRED: Call mcp__iranti__iranti_attend before every subsequent turn after that.',
|
|
265
|
+
].join('\n');
|
|
266
|
+
}
|
|
244
267
|
function extractSelfMemoryQueryKey(prompt) {
|
|
245
268
|
const normalized = prompt.trim();
|
|
246
269
|
if (!normalized)
|
|
@@ -258,18 +281,20 @@ function extractSelfMemoryQueryKey(prompt) {
|
|
|
258
281
|
function formatPromptContext(facts, prompt) {
|
|
259
282
|
if (facts.length === 0)
|
|
260
283
|
return '';
|
|
261
|
-
const
|
|
284
|
+
const structuredFacts = (0, hostMemoryFormatting_1.assignStructuredFactIds)(facts.map((fact) => ({
|
|
285
|
+
...fact,
|
|
286
|
+
entityKey: `${fact.entity}/${fact.key}`,
|
|
287
|
+
})));
|
|
288
|
+
const lines = [];
|
|
262
289
|
const targetKey = prompt ? extractSelfMemoryQueryKey(prompt) : null;
|
|
263
290
|
if (targetKey) {
|
|
264
|
-
const answerCandidate =
|
|
291
|
+
const answerCandidate = structuredFacts.find((fact) => (0, autoRemember_1.canonicalizeMemoryKey)(fact.entityKey.split('/').slice(2).join('/')) === targetKey);
|
|
265
292
|
if (answerCandidate) {
|
|
266
|
-
lines.push(`Direct
|
|
267
|
-
lines.push(
|
|
293
|
+
lines.push(`[Iranti Direct Answer]`);
|
|
294
|
+
lines.push(`Use ${answerCandidate.factId} directly if it fully answers the user question: ${answerCandidate.summary}.`);
|
|
268
295
|
}
|
|
269
296
|
}
|
|
270
|
-
|
|
271
|
-
lines.push(`- ${fact.entity}/${fact.key}: ${fact.summary}`);
|
|
272
|
-
}
|
|
297
|
+
lines.push((0, hostMemoryFormatting_1.formatStructuredFactBlock)(structuredFacts, { title: 'Iranti Retrieved Memory' }));
|
|
273
298
|
return lines.join('\n');
|
|
274
299
|
}
|
|
275
300
|
function emitHookContext(event, additionalContext) {
|
|
@@ -285,6 +310,10 @@ function shouldFetchMemory(prompt) {
|
|
|
285
310
|
const normalized = prompt.trim();
|
|
286
311
|
if (!normalized)
|
|
287
312
|
return false;
|
|
313
|
+
const explicitFacts = (0, autoRemember_1.extractExplicitPromptMemory)(normalized);
|
|
314
|
+
if (explicitFacts.some((fact) => fact.scope === 'project')) {
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
288
317
|
if (MEMORY_NEED_NEGATIVE_PATTERNS.some((pattern) => pattern.test(normalized))) {
|
|
289
318
|
return false;
|
|
290
319
|
}
|
|
@@ -294,7 +323,12 @@ function shouldFetchMemory(prompt) {
|
|
|
294
323
|
if (/\b(my|our|we)\b/i.test(normalized)) {
|
|
295
324
|
return true;
|
|
296
325
|
}
|
|
297
|
-
|
|
326
|
+
if (normalized.includes('/')) {
|
|
327
|
+
return true;
|
|
328
|
+
}
|
|
329
|
+
// Any substantive prompt in a project context should trigger memory fetch.
|
|
330
|
+
// Short acks and filler are already caught by MEMORY_NEED_NEGATIVE_PATTERNS.
|
|
331
|
+
return normalized.length > 20;
|
|
298
332
|
}
|
|
299
333
|
function dedupeFacts(facts) {
|
|
300
334
|
const byKey = new Map();
|
|
@@ -351,6 +385,9 @@ async function buildHookAdditionalContext(options) {
|
|
|
351
385
|
const cwd = getCwd(payload);
|
|
352
386
|
const agent = await ensureHookAgent(iranti, payload);
|
|
353
387
|
const entityHints = getEntityHints(payload);
|
|
388
|
+
if (event === 'PreCompact') {
|
|
389
|
+
return formatPreCompactContext();
|
|
390
|
+
}
|
|
354
391
|
if (event === 'SessionStart') {
|
|
355
392
|
const brief = await iranti.handshake({
|
|
356
393
|
agent,
|
|
@@ -365,12 +402,37 @@ async function buildHookAdditionalContext(options) {
|
|
|
365
402
|
}
|
|
366
403
|
if (event === 'Stop') {
|
|
367
404
|
const response = getLastAssistantMessage(payload);
|
|
368
|
-
if (response
|
|
369
|
-
await (0, autoRemember_1.
|
|
405
|
+
if (response) {
|
|
406
|
+
await (0, autoRemember_1.rememberAssistantResponseFacts)({
|
|
370
407
|
iranti,
|
|
371
408
|
response,
|
|
372
409
|
agent,
|
|
373
410
|
source: 'ClaudeCodeHookStop',
|
|
411
|
+
ledgerContext: {
|
|
412
|
+
source: 'claude_hook',
|
|
413
|
+
host: 'claude_code',
|
|
414
|
+
},
|
|
415
|
+
});
|
|
416
|
+
const checkpoint = (0, assistantCheckpoint_1.extractAssistantCheckpointPayload)(response);
|
|
417
|
+
const projectEntity = (0, autoRemember_1.getProjectMemoryEntity)();
|
|
418
|
+
if (checkpoint && projectEntity && typeof iranti.checkpoint === 'function') {
|
|
419
|
+
await iranti.checkpoint({
|
|
420
|
+
agent,
|
|
421
|
+
task: buildSessionTask(payload),
|
|
422
|
+
recentMessages: getRecentMessages(payload),
|
|
423
|
+
checkpoint: {
|
|
424
|
+
...checkpoint,
|
|
425
|
+
entityTargets: [projectEntity],
|
|
426
|
+
},
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
await iranti.attend({
|
|
430
|
+
agent,
|
|
431
|
+
latestMessage: response,
|
|
432
|
+
currentContext: response,
|
|
433
|
+
entityHints,
|
|
434
|
+
maxFacts: getMaxFacts(),
|
|
435
|
+
phase: 'post-response',
|
|
374
436
|
});
|
|
375
437
|
}
|
|
376
438
|
return '';
|
|
@@ -385,6 +447,10 @@ async function buildHookAdditionalContext(options) {
|
|
|
385
447
|
prompt,
|
|
386
448
|
agent,
|
|
387
449
|
source: 'ClaudeCodeHook',
|
|
450
|
+
ledgerContext: {
|
|
451
|
+
source: 'claude_hook',
|
|
452
|
+
host: 'claude_code',
|
|
453
|
+
},
|
|
388
454
|
});
|
|
389
455
|
}
|
|
390
456
|
if (!shouldFetchMemory(prompt)) {
|
|
@@ -396,6 +462,7 @@ async function buildHookAdditionalContext(options) {
|
|
|
396
462
|
currentContext: buildCurrentContext(payload, prompt),
|
|
397
463
|
entityHints,
|
|
398
464
|
maxFacts: getMaxFacts(),
|
|
465
|
+
phase: 'pre-response',
|
|
399
466
|
});
|
|
400
467
|
const facts = attend.facts.map((fact) => ({
|
|
401
468
|
entity: fact.entityKey.split('/').slice(0, 2).join('/'),
|
|
@@ -413,8 +480,8 @@ async function main() {
|
|
|
413
480
|
}
|
|
414
481
|
const args = parseArgs(process.argv.slice(2));
|
|
415
482
|
const event = args.event;
|
|
416
|
-
if (event !== 'SessionStart' && event !== 'UserPromptSubmit' && event !== 'Stop') {
|
|
417
|
-
throw new Error('--event must be SessionStart, UserPromptSubmit, or
|
|
483
|
+
if (event !== 'SessionStart' && event !== 'UserPromptSubmit' && event !== 'Stop' && event !== 'PreCompact') {
|
|
484
|
+
throw new Error('--event must be SessionStart, UserPromptSubmit, Stop, or PreCompact');
|
|
418
485
|
}
|
|
419
486
|
const payload = parsePayload(await readStdin());
|
|
420
487
|
(0, runtimeEnv_1.loadRuntimeEnv)({
|
|
@@ -426,24 +493,43 @@ async function main() {
|
|
|
426
493
|
const iranti = (0, createFirstPartyIranti_1.createFirstPartyIranti)({
|
|
427
494
|
connectionString: requireConnectionString(),
|
|
428
495
|
llmProvider: process.env.LLM_PROVIDER,
|
|
496
|
+
sessionLedgerSource: 'claude_hook',
|
|
497
|
+
sessionLedgerHost: 'claude_code',
|
|
429
498
|
});
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
499
|
+
let context = '';
|
|
500
|
+
try {
|
|
501
|
+
context = await buildHookAdditionalContext({
|
|
502
|
+
iranti,
|
|
503
|
+
event,
|
|
504
|
+
payload,
|
|
505
|
+
});
|
|
506
|
+
if (context) {
|
|
507
|
+
emitHookContext(event, context);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
finally {
|
|
511
|
+
await (0, staffEventRegistry_1.flushStaffEventEmitter)().catch(() => undefined);
|
|
512
|
+
await (0, client_1.disconnectDb)().catch(() => undefined);
|
|
438
513
|
}
|
|
439
|
-
emitHookContext(event, context);
|
|
440
|
-
await (0, staffEventRegistry_1.flushStaffEventEmitter)();
|
|
441
514
|
process.exit(0);
|
|
442
515
|
}
|
|
443
516
|
if (require.main === module) {
|
|
444
517
|
main().catch(async (error) => {
|
|
445
518
|
try {
|
|
519
|
+
(0, staffEventRegistry_1.getStaffEventEmitter)().emit({
|
|
520
|
+
staffComponent: 'Attendant',
|
|
521
|
+
actionType: 'host_failure',
|
|
522
|
+
agentId: process.env.IRANTI_CLAUDE_AGENT_ID?.trim() || 'claude_code',
|
|
523
|
+
source: 'claude_hook',
|
|
524
|
+
level: 'audit',
|
|
525
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
526
|
+
metadata: {
|
|
527
|
+
host: 'claude_code',
|
|
528
|
+
operation: 'hook_execution',
|
|
529
|
+
},
|
|
530
|
+
});
|
|
446
531
|
await (0, staffEventRegistry_1.flushStaffEventEmitter)();
|
|
532
|
+
await (0, client_1.disconnectDb)().catch(() => undefined);
|
|
447
533
|
}
|
|
448
534
|
catch { }
|
|
449
535
|
console.error('[claude-code-memory-hook] fatal:', error instanceof Error ? error.message : String(error));
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
7
7
|
const node_path_1 = __importDefault(require("node:path"));
|
|
8
8
|
const commandInvocation_1 = require("../src/lib/commandInvocation");
|
|
9
|
+
const scaffoldCloseout_1 = require("../src/lib/scaffoldCloseout");
|
|
9
10
|
function parseArgs(argv) {
|
|
10
11
|
const options = {
|
|
11
12
|
name: 'iranti',
|
|
@@ -82,7 +83,7 @@ function printHelp() {
|
|
|
82
83
|
' - Use --no-workspace-file only if you explicitly want global registration without project-local MCP file updates.',
|
|
83
84
|
' - Does not store DATABASE_URL in Codex config; iranti-mcp loads project/instance env at runtime.',
|
|
84
85
|
' - Replaces any existing MCP entry with the same name.',
|
|
85
|
-
' - Expected host pattern:
|
|
86
|
+
' - Expected host pattern: run iranti_handshake at session start, run iranti_attend before each reply and before/after knowledge discovery, checkpoint at natural pauses or interrupted work, and write/checkpoint confirmed findings.',
|
|
86
87
|
].join('\n'));
|
|
87
88
|
}
|
|
88
89
|
function run(command, args, cwd) {
|
|
@@ -164,6 +165,7 @@ function makeWorkspaceMcpServer(options, projectEnv) {
|
|
|
164
165
|
IRANTI_PROJECT_ENV: projectEnv,
|
|
165
166
|
IRANTI_MCP_DEFAULT_AGENT: options.agent,
|
|
166
167
|
IRANTI_MCP_DEFAULT_SOURCE: options.source,
|
|
168
|
+
IRANTI_MCP_HOST: 'codex_cli',
|
|
167
169
|
};
|
|
168
170
|
if (options.provider) {
|
|
169
171
|
env.LLM_PROVIDER = options.provider;
|
|
@@ -179,6 +181,7 @@ function makeVsCodeWorkspaceMcpServer(options, projectEnv) {
|
|
|
179
181
|
const env = {
|
|
180
182
|
IRANTI_MCP_DEFAULT_AGENT: options.agent,
|
|
181
183
|
IRANTI_MCP_DEFAULT_SOURCE: options.source,
|
|
184
|
+
IRANTI_MCP_HOST: 'codex_vscode',
|
|
182
185
|
};
|
|
183
186
|
if (options.provider) {
|
|
184
187
|
env.LLM_PROVIDER = options.provider;
|
|
@@ -197,6 +200,59 @@ function makeVsCodeWorkspaceMcpServer(options, projectEnv) {
|
|
|
197
200
|
env,
|
|
198
201
|
};
|
|
199
202
|
}
|
|
203
|
+
function buildCodexAgentsBlock() {
|
|
204
|
+
return [
|
|
205
|
+
'<!-- iranti-rules -->',
|
|
206
|
+
'# Iranti MCP Protocol',
|
|
207
|
+
'',
|
|
208
|
+
'IMPORTANT: These rules override Codex default behavior for this repo.',
|
|
209
|
+
'',
|
|
210
|
+
'## Session start',
|
|
211
|
+
'- Call `mcp__iranti__iranti_handshake` with the active task before responding to the first user message.',
|
|
212
|
+
'- If startup hooks are unavailable, do this on the first safe user turn instead of skipping it.',
|
|
213
|
+
'',
|
|
214
|
+
'## Discovery and reply ordering',
|
|
215
|
+
'- In short: call `mcp__iranti__iranti_attend` before each reply and before/after knowledge discovery.',
|
|
216
|
+
'1. Call `mcp__iranti__iranti_attend` before drafting each user-facing reply.',
|
|
217
|
+
'2. Call `mcp__iranti__iranti_attend` before using memory discovery tools such as search, query, or related reads.',
|
|
218
|
+
'3. Call `mcp__iranti__iranti_attend` again after discovery when the findings may change what should be injected, written, or checkpointed.',
|
|
219
|
+
'',
|
|
220
|
+
'## Confirmed findings',
|
|
221
|
+
'- Call `mcp__iranti__iranti_write` after confirmed durable findings such as decisions, blockers, next steps, stable constraints, validated environment details, what worked, what failed, and what remains risky.',
|
|
222
|
+
'- If the work is still in progress, pair those writes with `mcp__iranti__iranti_checkpoint` so another session can resume cleanly.',
|
|
223
|
+
'',
|
|
224
|
+
'## Checkpoint discipline',
|
|
225
|
+
'- Call `mcp__iranti__iranti_checkpoint` at natural pauses, before stepping away from long work, when interrupted, and when completing a useful slice.',
|
|
226
|
+
'- When useful actions happen, record them in the checkpoint `actions` field so later sessions can see important commands, tests, searches, validations, and decisions without rerunning them blindly.',
|
|
227
|
+
'- Do not treat durable writes as a substitute for checkpoints. A checkpoint not written means the next session has to reconstruct state.',
|
|
228
|
+
'- Under-logged runs are non-compliant for this repo. When applicable, leave structured breadcrumbs for what you found, what worked, what failed, what changed, and what happens next instead of only a broad summary.',
|
|
229
|
+
'',
|
|
230
|
+
'## Host setup check',
|
|
231
|
+
'- If this block was missing at session start, rerun `iranti codex-setup` from the bound project root.',
|
|
232
|
+
'<!-- /iranti-rules -->',
|
|
233
|
+
'',
|
|
234
|
+
].join('\n');
|
|
235
|
+
}
|
|
236
|
+
function writeWorkspaceAgentsFile(projectEnv) {
|
|
237
|
+
const projectPath = node_path_1.default.dirname(projectEnv);
|
|
238
|
+
const agentsFile = node_path_1.default.join(projectPath, 'AGENTS.md');
|
|
239
|
+
const irantiBlock = buildCodexAgentsBlock();
|
|
240
|
+
if (!node_fs_1.default.existsSync(agentsFile)) {
|
|
241
|
+
node_fs_1.default.writeFileSync(agentsFile, irantiBlock, 'utf8');
|
|
242
|
+
return { filePath: agentsFile, status: 'created' };
|
|
243
|
+
}
|
|
244
|
+
const existing = node_fs_1.default.readFileSync(agentsFile, 'utf8');
|
|
245
|
+
if (!existing.includes('<!-- iranti-rules -->')) {
|
|
246
|
+
node_fs_1.default.writeFileSync(agentsFile, `${existing.trimEnd()}\n\n${irantiBlock}`, 'utf8');
|
|
247
|
+
return { filePath: agentsFile, status: 'updated' };
|
|
248
|
+
}
|
|
249
|
+
const replaced = existing.replace(/<!-- iranti-rules -->[\s\S]*?<!-- \/iranti-rules -->/, irantiBlock.trim());
|
|
250
|
+
if (replaced === existing) {
|
|
251
|
+
return { filePath: agentsFile, status: 'unchanged' };
|
|
252
|
+
}
|
|
253
|
+
node_fs_1.default.writeFileSync(agentsFile, replaced, 'utf8');
|
|
254
|
+
return { filePath: agentsFile, status: 'updated' };
|
|
255
|
+
}
|
|
200
256
|
function writeWorkspaceMcpFile(projectEnv, options) {
|
|
201
257
|
const projectPath = node_path_1.default.dirname(projectEnv);
|
|
202
258
|
const mcpFile = node_path_1.default.join(projectPath, '.mcp.json');
|
|
@@ -292,7 +348,7 @@ function ensureCodexInstalled(repoRoot) {
|
|
|
292
348
|
throw new Error('Codex CLI is not installed or not on PATH. Install Codex first, confirm `codex --version` works, then rerun `iranti codex-setup`.');
|
|
293
349
|
}
|
|
294
350
|
}
|
|
295
|
-
function main() {
|
|
351
|
+
async function main() {
|
|
296
352
|
const options = parseArgs(process.argv.slice(2));
|
|
297
353
|
const repoRoot = findPackageRoot(__dirname);
|
|
298
354
|
const mcpScript = node_path_1.default.join(repoRoot, 'dist', 'scripts', 'iranti-mcp.js');
|
|
@@ -313,6 +369,8 @@ function main() {
|
|
|
313
369
|
`IRANTI_MCP_DEFAULT_AGENT=${options.agent}`,
|
|
314
370
|
'--env',
|
|
315
371
|
`IRANTI_MCP_DEFAULT_SOURCE=${options.source}`,
|
|
372
|
+
'--env',
|
|
373
|
+
'IRANTI_MCP_HOST=codex_cli',
|
|
316
374
|
];
|
|
317
375
|
const projectEnv = resolveProjectEnv(options);
|
|
318
376
|
if (projectEnv) {
|
|
@@ -335,13 +393,19 @@ function main() {
|
|
|
335
393
|
? {
|
|
336
394
|
mcp: writeWorkspaceMcpFile(workspaceProjectEnv, options),
|
|
337
395
|
vscode: writeWorkspaceVsCodeMcpFile(workspaceProjectEnv, options),
|
|
396
|
+
agents: writeWorkspaceAgentsFile(workspaceProjectEnv),
|
|
338
397
|
}
|
|
339
398
|
: null;
|
|
340
399
|
const registered = run('codex', ['mcp', 'get', options.name], repoRoot);
|
|
341
400
|
console.log(registered);
|
|
342
401
|
console.log('');
|
|
343
402
|
console.log('Codex is now configured to use Iranti through MCP.');
|
|
344
|
-
console.log('
|
|
403
|
+
console.log('Required host pattern:');
|
|
404
|
+
console.log(' 1. Run iranti_handshake at session start (or on the first safe user turn if startup hooks are unavailable).');
|
|
405
|
+
console.log(' 2. Run iranti_attend before each reply and before/after knowledge discovery.');
|
|
406
|
+
console.log(' 3. Run iranti_checkpoint at natural pauses, during interrupted work, and when completing a useful slice.');
|
|
407
|
+
console.log(' 4. Include key commands, tests, validations, and decisions in checkpoint actions when they matter to later recovery.');
|
|
408
|
+
console.log(' 5. Run iranti_write for confirmed durable findings, and pair ongoing work with iranti_checkpoint.');
|
|
345
409
|
if (useInstalled) {
|
|
346
410
|
console.log('Registration target: installed CLI (`iranti mcp`)');
|
|
347
411
|
if (projectEnv) {
|
|
@@ -365,13 +429,31 @@ function main() {
|
|
|
365
429
|
}
|
|
366
430
|
if (options.writeWorkspaceFile) {
|
|
367
431
|
if (workspaceFilesResult) {
|
|
432
|
+
const boundProjectEnv = workspaceProjectEnv;
|
|
368
433
|
console.log(`Workspace .mcp.json: ${workspaceFilesResult.mcp.status} (${workspaceFilesResult.mcp.filePath})`);
|
|
369
434
|
console.log(`Workspace .vscode/mcp.json: ${workspaceFilesResult.vscode.status} (${workspaceFilesResult.vscode.filePath})`);
|
|
435
|
+
console.log(`Workspace AGENTS.md: ${workspaceFilesResult.agents.status} (${workspaceFilesResult.agents.filePath})`);
|
|
436
|
+
const closeout = await (0, scaffoldCloseout_1.writeProjectScaffoldCloseout)({
|
|
437
|
+
tool: 'codex',
|
|
438
|
+
projectPath: node_path_1.default.dirname(boundProjectEnv),
|
|
439
|
+
projectEnvFile: boundProjectEnv,
|
|
440
|
+
files: [
|
|
441
|
+
{ path: workspaceFilesResult.mcp.filePath, status: workspaceFilesResult.mcp.status },
|
|
442
|
+
{ path: workspaceFilesResult.vscode.filePath, status: workspaceFilesResult.vscode.status },
|
|
443
|
+
{ path: workspaceFilesResult.agents.filePath, status: workspaceFilesResult.agents.status },
|
|
444
|
+
],
|
|
445
|
+
agentId: options.agent || 'codex_code',
|
|
446
|
+
});
|
|
447
|
+
console.log(`Shared memory closeout: ${closeout.status} (${closeout.detail})`);
|
|
370
448
|
}
|
|
371
449
|
else {
|
|
372
450
|
console.log('Workspace MCP files: unchanged (no project binding found from the current working directory)');
|
|
451
|
+
console.log('Shared memory closeout: skipped (no bound workspace project was found)');
|
|
373
452
|
}
|
|
374
453
|
}
|
|
375
454
|
}
|
|
376
|
-
main()
|
|
455
|
+
main().catch((error) => {
|
|
456
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
457
|
+
process.exit(1);
|
|
458
|
+
});
|
|
377
459
|
//# sourceMappingURL=codex-setup.js.map
|