nativesoul 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/LICENSE +19 -0
  3. package/README.md +384 -0
  4. package/dist/packages/cli/src/index.js +1066 -0
  5. package/dist/packages/core/src/secret-patterns.json +25 -0
  6. package/dist/packages/mcp-server/src/index.js +782 -0
  7. package/docs/adr/ADR-001-node-first-runtime.md +20 -0
  8. package/docs/adr/ADR-002-workspace-and-state.md +16 -0
  9. package/docs/adr/ADR-003-schemas-and-adapter-sdk.md +15 -0
  10. package/docs/adr/ADR-004-policy-leases-and-heartbeat.md +15 -0
  11. package/docs/adr/ADR-005-privacy-export-delete-and-supply-chain.md +16 -0
  12. package/docs/adr/ADR-006-adapter-preview-before-install.md +21 -0
  13. package/docs/adr/ADR-007-managed-block-backup-and-rollback.md +16 -0
  14. package/docs/adr/ADR-008-mcp-registration-manifest-before-write.md +16 -0
  15. package/docs/adr/ADR-009-local-capability-registry.md +16 -0
  16. package/docs/adr/ADR-010-mcp-capability-tools-read-only.md +15 -0
  17. package/docs/adr/ADR-011-local-audit-cli-export.md +16 -0
  18. package/docs/adr/ADR-012-npm-package-runtime-scope.md +16 -0
  19. package/docs/adr/ADR-013-core-domain-ledger-v1.md +16 -0
  20. package/docs/adr/ADR-014-memory-lifecycle-v1.md +16 -0
  21. package/docs/adr/ADR-015-policy-standing-orders-v1.md +16 -0
  22. package/docs/adr/ADR-016-heartbeat-lease-idempotency-v1.md +16 -0
  23. package/docs/adr/ADR-017-reversible-mcp-registration-install.md +17 -0
  24. package/docs/adr/ADR-018-schedule-reconcile-guardrails-v1.md +17 -0
  25. package/docs/adr/ADR-019-commitments-lifecycle-v1.md +17 -0
  26. package/docs/adr/ADR-020-mcp-memory-lifecycle-tools.md +16 -0
  27. package/docs/adr/ADR-021-unified-install-orchestrator-v1.md +17 -0
  28. package/docs/adr/ADR-022-unified-uninstall-orchestrator-v1.md +20 -0
  29. package/docs/adr/ADR-023-deep-doctor-install-readiness-v1.md +18 -0
  30. package/docs/adr/ADR-024-capability-learn-cards-v1.md +18 -0
  31. package/docs/adr/ADR-025-bootstrap-capability-card-recall-v1.md +18 -0
  32. package/docs/adr/ADR-026-managed-block-bootstrap-handshake-v1.md +18 -0
  33. package/docs/adr/ADR-027-local-release-manifest-checksum-v1.md +17 -0
  34. package/docs/adr/ADR-028-openclaw-workspace-templates-v1.md +47 -0
  35. package/docs/adr/ADR-029-host-guided-onboarding-v1.md +98 -0
  36. package/docs/adr/ADR-030-host-surface-matrix-v1.md +93 -0
  37. package/docs/adr/ADR-031-host-parity-matrix-v2.md +91 -0
  38. package/docs/adr/ADR-032-nativesoul-hard-cut-rebrand.md +54 -0
  39. package/docs/adr/ADR-033-local-hybrid-memory-reflection.md +49 -0
  40. package/docs/adr/ADR-034-memory-importers-provenance.md +38 -0
  41. package/docs/adr/ADR-035-policy-pack-apply-rollback.md +34 -0
  42. package/docs/adr/ADR-036-local-operator-dashboard-readonly.md +38 -0
  43. package/docs/adr/ADR-037-full-native-evidence-contract.md +45 -0
  44. package/docs/adr/ADR-038-identity-vs-activation-onboarding.md +39 -0
  45. package/docs/adr/ADR-039-entitlements-offline-licensing.md +47 -0
  46. package/docs/adr/ADR-040-proprietary-free-to-install-distribution.md +52 -0
  47. package/docs/adr/ADR-041-project-identity-and-lightweight-registry.md +35 -0
  48. package/docs/adr/ADR-042-control-plane-direction-and-deferral.md +80 -0
  49. package/docs/adr/ADR-043-versioning-and-release-policy.md +60 -0
  50. package/docs/adr/ADR-044-pro-awareness-and-upgrade-nudge-policy.md +53 -0
  51. package/docs/adr/ADR-045-paid-only-closed-distribution.md +55 -0
  52. package/docs/legal/EULA.md +70 -0
  53. package/llm-install.txt +222 -0
  54. package/package.json +61 -0
  55. package/plugins/antigravity-nativesoul/GEMINI.md +17 -0
  56. package/plugins/antigravity-nativesoul/commands/nativesoul-explore.md +22 -0
  57. package/plugins/antigravity-nativesoul/commands/nativesoul-heartbeat.md +9 -0
  58. package/plugins/antigravity-nativesoul/commands/nativesoul-plan.md +23 -0
  59. package/plugins/antigravity-nativesoul/commands/nativesoul-recall.md +16 -0
  60. package/plugins/antigravity-nativesoul/commands/nativesoul-start.md +9 -0
  61. package/plugins/antigravity-nativesoul/hooks.json +59 -0
  62. package/plugins/antigravity-nativesoul/mcp_config.json +8 -0
  63. package/plugins/antigravity-nativesoul/nativesoul-package.json +22 -0
  64. package/plugins/antigravity-nativesoul/plugin.json +5 -0
  65. package/plugins/claude-nativesoul/.claude-plugin/plugin.json +90 -0
  66. package/plugins/claude-nativesoul/hooks/loader.cjs +23 -0
  67. package/plugins/claude-nativesoul/hooks/memory-flush.cjs +45 -0
  68. package/plugins/claude-nativesoul/hooks/pre-tool-use.cjs +53 -0
  69. package/plugins/claude-nativesoul/hooks/session-start.cjs +108 -0
  70. package/plugins/claude-nativesoul/hooks/user-prompt-submit.cjs +62 -0
  71. package/plugins/claude-nativesoul/skills/life-explore/SKILL.md +19 -0
  72. package/plugins/claude-nativesoul/skills/life-heartbeat/SKILL.md +16 -0
  73. package/plugins/claude-nativesoul/skills/life-plan/SKILL.md +23 -0
  74. package/plugins/claude-nativesoul/skills/life-recall/SKILL.md +18 -0
  75. package/plugins/claude-nativesoul/skills/life-start/SKILL.md +13 -0
  76. package/plugins/codex-nativesoul/.codex-plugin/plugin.json +83 -0
  77. package/plugins/codex-nativesoul/.mcp.json +8 -0
  78. package/plugins/codex-nativesoul/hooks/loader.cjs +23 -0
  79. package/plugins/codex-nativesoul/hooks/memory-flush.cjs +45 -0
  80. package/plugins/codex-nativesoul/hooks/pre-tool-use.cjs +53 -0
  81. package/plugins/codex-nativesoul/hooks/session-start.cjs +119 -0
  82. package/plugins/codex-nativesoul/hooks/user-prompt-submit.cjs +62 -0
  83. package/plugins/codex-nativesoul/skills/life-explore/SKILL.md +24 -0
  84. package/plugins/codex-nativesoul/skills/life-heartbeat/SKILL.md +21 -0
  85. package/plugins/codex-nativesoul/skills/life-plan/SKILL.md +28 -0
  86. package/plugins/codex-nativesoul/skills/life-recall/SKILL.md +23 -0
  87. package/plugins/codex-nativesoul/skills/life-start/SKILL.md +18 -0
  88. package/plugins/gemini-nativesoul/GEMINI.md +17 -0
  89. package/plugins/gemini-nativesoul/commands/nativesoul-explore.toml +3 -0
  90. package/plugins/gemini-nativesoul/commands/nativesoul-heartbeat.toml +2 -0
  91. package/plugins/gemini-nativesoul/commands/nativesoul-plan.toml +3 -0
  92. package/plugins/gemini-nativesoul/commands/nativesoul-recall.toml +3 -0
  93. package/plugins/gemini-nativesoul/commands/nativesoul-start.toml +2 -0
  94. package/plugins/gemini-nativesoul/gemini-extension.json +16 -0
  95. package/plugins/gemini-nativesoul/hooks/hooks.json +59 -0
  96. package/plugins/grok-nativesoul/.mcp.json +8 -0
  97. package/plugins/grok-nativesoul/AGENTS.md +17 -0
  98. package/plugins/grok-nativesoul/commands/nativesoul-explore.md +22 -0
  99. package/plugins/grok-nativesoul/commands/nativesoul-heartbeat.md +9 -0
  100. package/plugins/grok-nativesoul/commands/nativesoul-plan.md +23 -0
  101. package/plugins/grok-nativesoul/commands/nativesoul-recall.md +16 -0
  102. package/plugins/grok-nativesoul/commands/nativesoul-start.md +9 -0
  103. package/plugins/grok-nativesoul/hooks/hooks.json +59 -0
  104. package/plugins/grok-nativesoul/nativesoul-package.json +22 -0
  105. package/plugins/grok-nativesoul/plugin.json +5 -0
  106. package/plugins/shared/hooks/host-hook.cjs +207 -0
  107. package/plugins/shared/hooks/lib.cjs +279 -0
  108. package/plugins/shared/hooks/policy-fail-closed.cjs +95 -0
  109. package/policy-packs/local-readonly.json +47 -0
  110. package/policy-packs/team-review.json +49 -0
  111. package/schemas/audit-event.schema.json +18 -0
  112. package/schemas/capability-card.schema.json +37 -0
  113. package/schemas/capability.schema.json +25 -0
  114. package/schemas/commitment.schema.json +19 -0
  115. package/schemas/full-native-evidence.schema.json +82 -0
  116. package/schemas/lease.schema.json +16 -0
  117. package/schemas/memory.schema.json +31 -0
  118. package/schemas/migration.schema.json +14 -0
  119. package/schemas/policy-pack.schema.json +96 -0
  120. package/schemas/schedule.schema.json +16 -0
  121. package/schemas/session.schema.json +16 -0
@@ -0,0 +1,22 @@
1
+ # nativesoul-explore
2
+
3
+ Explore the current project with NativeSoul context.
4
+
5
+ Default policy: read-only and bounded. Do not edit files, install packages, start services, create schedulers, or perform external writes.
6
+
7
+ 1. Call MCP `life_bootstrap` with `host="grok"`.
8
+ 2. Inspect readiness with:
9
+
10
+ ```bash
11
+ nativesoul dashboard data --host grok --limit 25 --json
12
+ ```
13
+
14
+ 3. Scope discovery to the operator request. Prefer targeted local reads:
15
+
16
+ ```bash
17
+ rg --files
18
+ rg "<specific term from the task>"
19
+ ```
20
+
21
+ 4. Avoid broad unbounded scans. If a write is needed, stop and ask for normal approval.
22
+
@@ -0,0 +1,9 @@
1
+ # nativesoul-heartbeat
2
+
3
+ Run a heartbeat tick without creating a hidden scheduler:
4
+
5
+ 1. Claim a lease with host `grok`.
6
+ 2. If the result is `HEARTBEAT_OK`, stay silent.
7
+ 3. Complete only leases won by Grok.
8
+
9
+ Native schedule status remains `native_schedule_supported=false` until Grok documents an official scheduler surface.
@@ -0,0 +1,23 @@
1
+ # nativesoul-plan
2
+
3
+ Build a NativeSoul-aware plan for the current Grok task.
4
+
5
+ Default policy: read-only.
6
+
7
+ 1. Call MCP `life_bootstrap` with `host="grok"` and the current working directory.
8
+ 2. Read dashboard state:
9
+
10
+ ```bash
11
+ nativesoul dashboard data --host grok --limit 25 --json
12
+ ```
13
+
14
+ 3. Read commitments and capabilities when relevant:
15
+
16
+ ```bash
17
+ nativesoul commitments list --project <project-id> --status open --limit 25 --json
18
+ nativesoul capabilities list --host grok --limit 25 --json
19
+ ```
20
+
21
+ 4. Separate implemented, degraded/fallback, and approval-required work.
22
+ 5. Do not mutate schedules, memory, policy, or files without explicit approval.
23
+
@@ -0,0 +1,16 @@
1
+ # nativesoul-recall
2
+
3
+ Recall NativeSoul project memory and capability context for the current Grok task.
4
+
5
+ Default policy: read-only.
6
+
7
+ 1. Prefer MCP `life_recall` with `host="grok"` and the current working directory.
8
+ 2. If MCP is unavailable, run:
9
+
10
+ ```bash
11
+ nativesoul memory recall-hook --host grok --cwd "$PWD" --prompt "<task query>" --limit 8 --json
12
+ ```
13
+
14
+ 3. Treat recovered memory as advisory and verify against files.
15
+ 4. Report readiness honestly as `ready`, `full native capability`, `official-fallback`, or `degraded`.
16
+
@@ -0,0 +1,9 @@
1
+ # nativesoul-start
2
+
3
+ Call MCP `life_bootstrap` with `host="grok"` and the current working directory.
4
+
5
+ If MCP is unavailable, run:
6
+
7
+ ```bash
8
+ nativesoul bootstrap --host grok --cwd "$PWD" --format inject --json
9
+ ```
@@ -0,0 +1,59 @@
1
+ {
2
+ "hooks": {
3
+ "SessionStart": [
4
+ {
5
+ "hooks": [
6
+ {
7
+ "type": "command",
8
+ "command": "node \"$GROK_PLUGIN_ROOT/shared/hooks/host-hook.cjs\" session-start --host grok --project-env GROK_WORKSPACE_ROOT",
9
+ "timeout": 9
10
+ }
11
+ ]
12
+ }
13
+ ],
14
+ "UserPromptSubmit": [
15
+ {
16
+ "hooks": [
17
+ {
18
+ "type": "command",
19
+ "command": "node \"$GROK_PLUGIN_ROOT/shared/hooks/host-hook.cjs\" prompt-bootstrap --host grok --project-env GROK_WORKSPACE_ROOT",
20
+ "timeout": 9
21
+ }
22
+ ]
23
+ }
24
+ ],
25
+ "PreToolUse": [
26
+ {
27
+ "hooks": [
28
+ {
29
+ "type": "command",
30
+ "command": "node \"$GROK_PLUGIN_ROOT/shared/hooks/host-hook.cjs\" pre-tool-use --host grok --project-env GROK_WORKSPACE_ROOT",
31
+ "timeout": 9
32
+ }
33
+ ]
34
+ }
35
+ ],
36
+ "Stop": [
37
+ {
38
+ "hooks": [
39
+ {
40
+ "type": "command",
41
+ "command": "node \"$GROK_PLUGIN_ROOT/shared/hooks/host-hook.cjs\" memory-flush --host grok --project-env GROK_WORKSPACE_ROOT",
42
+ "timeout": 9
43
+ }
44
+ ]
45
+ }
46
+ ],
47
+ "PreCompact": [
48
+ {
49
+ "hooks": [
50
+ {
51
+ "type": "command",
52
+ "command": "node \"$GROK_PLUGIN_ROOT/shared/hooks/host-hook.cjs\" memory-flush --host grok --project-env GROK_WORKSPACE_ROOT",
53
+ "timeout": 9
54
+ }
55
+ ]
56
+ }
57
+ ]
58
+ }
59
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "grok-nativesoul",
3
+ "version": "0.1.0",
4
+ "nativeSoul": {
5
+ "host": "grok",
6
+ "packageKind": "native-plugin",
7
+ "nativeHooksSupported": true,
8
+ "nativeSchedulerSupported": false,
9
+ "mcpServer": {
10
+ "name": "nativesoul",
11
+ "command": "nativesoul-mcp",
12
+ "args": []
13
+ },
14
+ "commands": [
15
+ "nativesoul-start",
16
+ "nativesoul-heartbeat",
17
+ "nativesoul-recall",
18
+ "nativesoul-plan",
19
+ "nativesoul-explore"
20
+ ]
21
+ }
22
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "nativesoul",
3
+ "version": "0.1.0",
4
+ "description": "NativeSoul continuity, memory, policy, and MCP bootstrap for Grok."
5
+ }
@@ -0,0 +1,207 @@
1
+ 'use strict';
2
+
3
+ const lib = require('./lib.cjs');
4
+ const policy = require('./policy-fail-closed.cjs');
5
+
6
+ const kind = (process.argv[2] || 'session-start').trim();
7
+ const options = parseOptions(process.argv.slice(3));
8
+ const host = (options.host || process.env.NATIVESOUL_HOOK_HOST || 'codex').trim();
9
+ const projectEnv = (options.projectEnv || process.env.NATIVESOUL_PROJECT_ENV || defaultProjectEnv(host)).trim();
10
+ const eventName = (options.event || process.env.NATIVESOUL_HOOK_EVENT_NAME || '').trim();
11
+
12
+ function parseOptions(args) {
13
+ const parsed = {};
14
+ for (let index = 0; index < args.length; index += 1) {
15
+ const arg = args[index];
16
+ if (arg === '--host' && args[index + 1]) {
17
+ parsed.host = args[index + 1];
18
+ index += 1;
19
+ continue;
20
+ }
21
+ if (arg === '--project-env' && args[index + 1]) {
22
+ parsed.projectEnv = args[index + 1];
23
+ index += 1;
24
+ continue;
25
+ }
26
+ if (arg === '--event' && args[index + 1]) {
27
+ parsed.event = args[index + 1];
28
+ index += 1;
29
+ }
30
+ }
31
+ return parsed;
32
+ }
33
+
34
+ function defaultProjectEnv(currentHost) {
35
+ if (currentHost === 'codex') {
36
+ return 'CODEX_PROJECT_DIR';
37
+ }
38
+ if (currentHost === 'grok') {
39
+ return 'GROK_WORKSPACE_ROOT';
40
+ }
41
+ if (currentHost === 'gemini' || currentHost === 'antigravity') {
42
+ return 'GEMINI_CWD';
43
+ }
44
+ return 'CLAUDE_PROJECT_DIR';
45
+ }
46
+
47
+ function jsonOutput(value) {
48
+ process.stdout.write(`${JSON.stringify(value)}\n`);
49
+ }
50
+
51
+ function hookEventName(input, fallback) {
52
+ return eventName || input.hook_event_name || input.hookEventName || input.event_name || input.eventName || process.env.GROK_HOOK_EVENT || fallback;
53
+ }
54
+
55
+ function bootstrapContext(cwd) {
56
+ const injectArgs = lib.appendHomeArg(['bootstrap', '--host', host, '--cwd', cwd, '--format', 'inject', '--json']);
57
+ const inject = lib.spawnNativeSoul(injectArgs);
58
+ const injectJson = lib.parseJsonStdout(inject);
59
+ if (injectJson && typeof injectJson.content === 'string') {
60
+ return {
61
+ content: injectJson.content,
62
+ degraded: false,
63
+ source: 'inject',
64
+ warnings: Array.isArray(injectJson.warnings) ? injectJson.warnings : []
65
+ };
66
+ }
67
+
68
+ const cacheArgs = lib.appendHomeArg(['bootstrap', '--host', host, '--cwd', cwd, '--format', 'cache', '--json']);
69
+ const cache = lib.spawnNativeSoul(cacheArgs);
70
+ const cacheJson = lib.parseJsonStdout(cache);
71
+ if (cacheJson && typeof cacheJson.content === 'string') {
72
+ return {
73
+ content: cacheJson.content,
74
+ degraded: true,
75
+ source: 'cache',
76
+ warnings: Array.isArray(cacheJson.warnings) ? cacheJson.warnings : []
77
+ };
78
+ }
79
+
80
+ return null;
81
+ }
82
+
83
+ function outputBootstrapContext(input, fallbackEvent) {
84
+ const cwd = lib.resolveProjectDir(input, projectEnv);
85
+ const context = bootstrapContext(cwd);
86
+ if (!context || context.content.trim().length === 0) {
87
+ return;
88
+ }
89
+ const hookName = hookEventName(input, fallbackEvent);
90
+ jsonOutput({
91
+ context: context.content,
92
+ degraded: context.degraded,
93
+ source: context.source,
94
+ warnings: context.warnings,
95
+ hookSpecificOutput: {
96
+ hookEventName: hookName,
97
+ additionalContext: context.content
98
+ }
99
+ });
100
+ }
101
+
102
+ function runRecallHook(input) {
103
+ const prompt = input.prompt || input.userPrompt || input.message || '';
104
+ if (typeof prompt !== 'string' || prompt.trim().length === 0) {
105
+ return null;
106
+ }
107
+ const cwd = lib.resolveProjectDir(input, projectEnv);
108
+ const args = lib.appendHomeArg(['memory', 'recall-hook', '--host', host, '--cwd', cwd, '--json']);
109
+ const result = lib.spawnNativeSoul(args, { input: `${JSON.stringify(input)}\n` });
110
+ const json = lib.parseJsonStdout(result);
111
+ if (!json || typeof json.context !== 'string' || json.context.trim().length === 0) {
112
+ return null;
113
+ }
114
+ return json.context.trim();
115
+ }
116
+
117
+ function recallContext(input) {
118
+ const recall = runRecallHook(input);
119
+ if (!recall) {
120
+ return;
121
+ }
122
+ jsonOutput({
123
+ hookSpecificOutput: {
124
+ hookEventName: hookEventName(input, 'UserPromptSubmit'),
125
+ additionalContext: recall
126
+ }
127
+ });
128
+ }
129
+
130
+ function outputPromptBootstrap(input, fallbackEvent) {
131
+ const cwd = lib.resolveProjectDir(input, projectEnv);
132
+ const bootstrap = bootstrapContext(cwd);
133
+ const recall = runRecallHook(input);
134
+ const parts = [];
135
+ if (bootstrap && typeof bootstrap.content === 'string' && bootstrap.content.trim().length > 0) {
136
+ parts.push(bootstrap.content.trim());
137
+ }
138
+ if (recall) {
139
+ parts.push(recall);
140
+ }
141
+ if (parts.length === 0) {
142
+ return;
143
+ }
144
+ const combined = parts.join('\n\n');
145
+ const hookName = hookEventName(input, fallbackEvent);
146
+ jsonOutput({
147
+ context: combined,
148
+ degraded: bootstrap ? bootstrap.degraded : false,
149
+ source: bootstrap ? bootstrap.source : 'recall',
150
+ warnings: bootstrap && Array.isArray(bootstrap.warnings) ? bootstrap.warnings : [],
151
+ hookSpecificOutput: {
152
+ hookEventName: hookName,
153
+ additionalContext: combined
154
+ }
155
+ });
156
+ }
157
+
158
+ function evaluatePreToolUse(input) {
159
+ const cwd = lib.resolveProjectDir(input, projectEnv);
160
+ const payload = JSON.stringify(input);
161
+ const args = lib.appendHomeArg(['policy', 'evaluate-pre-tool-use', '--host', host, '--cwd', cwd, '--json']);
162
+ const cliResult = lib.spawnNativeSoul(args, { input: payload });
163
+ const result = lib.parseJsonStdout(cliResult) || policy.evaluate(input);
164
+ const output = lib.buildPreToolUseHookOutput(result);
165
+ if (output) {
166
+ jsonOutput({
167
+ ...output,
168
+ hookSpecificOutput: {
169
+ ...output.hookSpecificOutput,
170
+ hookEventName: hookEventName(input, 'PreToolUse')
171
+ }
172
+ });
173
+ }
174
+ }
175
+
176
+ function flushMemory(input) {
177
+ const cwd = lib.resolveProjectDir(input, projectEnv);
178
+ const args = lib.appendHomeArg(['memory', 'flush-hook', '--host', host, '--cwd', cwd, '--json']);
179
+ const result = lib.spawnNativeSoul(args, { input: JSON.stringify(input) });
180
+ const json = lib.parseJsonStdout(result);
181
+ if (json) {
182
+ jsonOutput({ nativeSoul: json });
183
+ }
184
+ }
185
+
186
+ lib.runNonBlocking(async () => {
187
+ const input = await lib.readStdin({ fallback: (raw) => ({ raw }) });
188
+ if (kind === 'session-start') {
189
+ outputBootstrapContext(input, 'SessionStart');
190
+ return;
191
+ }
192
+ if (kind === 'prompt-bootstrap') {
193
+ outputPromptBootstrap(input, 'UserPromptSubmit');
194
+ return;
195
+ }
196
+ if (kind === 'recall') {
197
+ recallContext(input);
198
+ return;
199
+ }
200
+ if (kind === 'pre-tool-use') {
201
+ evaluatePreToolUse(input);
202
+ return;
203
+ }
204
+ if (kind === 'memory-flush') {
205
+ flushMemory(input);
206
+ }
207
+ });
@@ -0,0 +1,279 @@
1
+ 'use strict';
2
+
3
+ const { spawnSync } = require('node:child_process');
4
+ const fs = require('node:fs');
5
+ const path = require('node:path');
6
+
7
+ const DEFAULT_HOOK_TIMEOUT_MS = 9000;
8
+ const PROJECT_CACHE_DIR = '.nativesoul-cache';
9
+
10
+ function claudeDesktopConfigPath(homeDir) {
11
+ if (process.platform === 'darwin') {
12
+ return path.join(homeDir, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
13
+ }
14
+ if (process.platform === 'win32') {
15
+ const appData = process.env.APPDATA && process.env.APPDATA.trim().length > 0
16
+ ? process.env.APPDATA
17
+ : path.join(homeDir, 'AppData', 'Roaming');
18
+ return path.join(appData, 'Claude', 'claude_desktop_config.json');
19
+ }
20
+ const configHome = process.env.XDG_CONFIG_HOME && process.env.XDG_CONFIG_HOME.trim().length > 0
21
+ ? process.env.XDG_CONFIG_HOME
22
+ : path.join(homeDir, '.config');
23
+ return path.join(configHome, 'Claude', 'claude_desktop_config.json');
24
+ }
25
+
26
+ function defaultMcpConfigCandidates(homeDir) {
27
+ return [
28
+ path.join(homeDir, '.claude', 'mcp.json'),
29
+ path.join(homeDir, '.claude.json'),
30
+ path.join(homeDir, '.codex', 'mcp.json'),
31
+ path.join(homeDir, '.gemini', 'settings.json'),
32
+ path.join(homeDir, '.gemini', 'mcp.json'),
33
+ path.join(homeDir, '.gemini', 'config', 'mcp_config.json'),
34
+ path.join(homeDir, '.gemini', 'antigravity-cli', 'mcp_config.json'),
35
+ path.join(homeDir, '.gemini', 'antigravity', 'mcp_config.json'),
36
+ path.join(homeDir, '.gemini', 'antigravity-ide', 'mcp_config.json'),
37
+ path.join(homeDir, '.grok', 'mcp.json'),
38
+ path.join(homeDir, '.antigravity', 'mcp.json'),
39
+ claudeDesktopConfigPath(homeDir)
40
+ ];
41
+ }
42
+
43
+ function resolveNativeSoulCli(options = {}) {
44
+ if (process.env.NATIVESOUL_CLI) {
45
+ return process.env.NATIVESOUL_CLI;
46
+ }
47
+ const homeDir = process.env.HOME || process.env.USERPROFILE;
48
+ if (!homeDir) {
49
+ return 'nativesoul';
50
+ }
51
+ const candidates = options.configPaths ?? defaultMcpConfigCandidates(homeDir);
52
+ for (const configPath of candidates) {
53
+ try {
54
+ if (fs.existsSync(configPath)) {
55
+ const content = JSON.parse(fs.readFileSync(configPath, 'utf8'));
56
+ const mcpCommand = content?.mcpServers?.['nativesoul']?.command;
57
+ if (typeof mcpCommand === 'string' && mcpCommand.includes('nativesoul-mcp')) {
58
+ const cliCommand = mcpCommand.replace('nativesoul-mcp', 'nativesoul');
59
+ if (fs.existsSync(cliCommand)) {
60
+ return cliCommand;
61
+ }
62
+ }
63
+ }
64
+ } catch {
65
+ // Ignore malformed MCP config.
66
+ }
67
+ }
68
+ return 'nativesoul';
69
+ }
70
+
71
+ function readStdin(options = {}) {
72
+ const fallback = options.fallback ?? (() => ({}));
73
+ return new Promise((resolve) => {
74
+ let data = '';
75
+ process.stdin.setEncoding('utf8');
76
+ process.stdin.on('data', (chunk) => {
77
+ data += chunk;
78
+ });
79
+ process.stdin.on('end', () => {
80
+ if (data.trim().length === 0) {
81
+ resolve({});
82
+ return;
83
+ }
84
+ try {
85
+ resolve(JSON.parse(data));
86
+ } catch {
87
+ resolve(fallback(data));
88
+ }
89
+ });
90
+ });
91
+ }
92
+
93
+ function resolveProjectDir(input, envVarName) {
94
+ const common = input && !Array.isArray(input) && typeof input === 'object'
95
+ ? input.common
96
+ : null;
97
+ const commonWorkspace = common && !Array.isArray(common) && typeof common === 'object'
98
+ ? common.workspaceRoot || common.workspace_root || (Array.isArray(common.workspacePaths) ? common.workspacePaths[0] : null) || (Array.isArray(common.workspace_paths) ? common.workspace_paths[0] : null)
99
+ : null;
100
+ return input.cwd ||
101
+ input.workspaceRoot ||
102
+ input.workspace_root ||
103
+ input.project_dir ||
104
+ commonWorkspace ||
105
+ process.env.NATIVESOUL_CWD ||
106
+ process.env[envVarName] ||
107
+ process.env.CLAUDE_PROJECT_DIR ||
108
+ process.env.GROK_WORKSPACE_ROOT ||
109
+ process.env.GEMINI_CWD ||
110
+ process.env.GEMINI_PROJECT_DIR ||
111
+ process.cwd();
112
+ }
113
+
114
+ function appendHomeArg(args) {
115
+ const home = process.env.NATIVESOUL_HOME;
116
+ if (home && home.trim().length > 0) {
117
+ args.push('--home', home.trim());
118
+ }
119
+ return args;
120
+ }
121
+
122
+ function spawnNativeSoul(args, options = {}) {
123
+ const command = resolveNativeSoulCli(options.resolveOptions);
124
+ const isNodeScript = /\.(?:cjs|mjs|js)$/iu.test(command);
125
+ const spawnCommand = isNodeScript ? process.execPath : command;
126
+ const spawnArgs = isNodeScript ? [command, ...args] : args;
127
+ const shell = process.platform === 'win32' && /\.(?:cmd|bat)$/iu.test(spawnCommand);
128
+ return spawnSync(spawnCommand, spawnArgs, {
129
+ input: options.input,
130
+ encoding: 'utf8',
131
+ timeout: options.timeout ?? DEFAULT_HOOK_TIMEOUT_MS,
132
+ env: process.env,
133
+ stdio: options.stdio ?? ['pipe', 'pipe', 'pipe'],
134
+ shell
135
+ });
136
+ }
137
+
138
+ function projectFallbackBootstrapHome(cwd) {
139
+ return path.join(cwd, PROJECT_CACHE_DIR);
140
+ }
141
+
142
+ function projectBootstrapCachePath(cwd, host) {
143
+ return path.join(projectFallbackBootstrapHome(cwd), 'generated', host, 'last-context.md');
144
+ }
145
+
146
+ function hasCacheWriteSkippedWarning(context) {
147
+ return Array.isArray(context?.warnings) &&
148
+ context.warnings.some((warning) => typeof warning === 'string' && warning.startsWith('BOOTSTRAP_CACHE_WRITE_SKIPPED:'));
149
+ }
150
+
151
+ function removeCacheWriteSkippedWarning(content) {
152
+ const withoutSkipped = content.replace(/^warnings: (.+)$/mu, (_line, value) => {
153
+ const warnings = String(value)
154
+ .split(',')
155
+ .map((item) => item.trim())
156
+ .filter((item) => item.length > 0 && !item.startsWith('BOOTSTRAP_CACHE_WRITE_SKIPPED:'));
157
+ return warnings.length > 0 ? `warnings: ${warnings.join(', ')}` : 'warnings: none';
158
+ });
159
+ return withoutSkipped.replace(/^degraded: true$/mu, 'degraded: false');
160
+ }
161
+
162
+ function writeProjectFallbackCache(input) {
163
+ const { context, cwd, host } = input;
164
+ if (!context || typeof context.content !== 'string' || !hasCacheWriteSkippedWarning(context)) {
165
+ return context;
166
+ }
167
+ const sanitizedContent = removeCacheWriteSkippedWarning(context.content);
168
+ try {
169
+ const targetPath = projectBootstrapCachePath(cwd, host);
170
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true, mode: 0o700 });
171
+ const tempPath = path.join(path.dirname(targetPath), `.last-context-${Date.now()}-${process.pid}.tmp`);
172
+ fs.writeFileSync(tempPath, sanitizedContent, { encoding: 'utf8', mode: 0o600 });
173
+ fs.renameSync(tempPath, targetPath);
174
+ const warnings = Array.isArray(context.warnings)
175
+ ? context.warnings.filter((warning) => typeof warning !== 'string' || !warning.startsWith('BOOTSTRAP_CACHE_WRITE_SKIPPED:'))
176
+ : [];
177
+ return {
178
+ ...context,
179
+ degraded: false,
180
+ warnings,
181
+ content: sanitizedContent,
182
+ projectFallbackCachePath: targetPath
183
+ };
184
+ } catch {
185
+ return context;
186
+ }
187
+ }
188
+
189
+ function readProjectFallbackCache(input) {
190
+ try {
191
+ const targetPath = projectBootstrapCachePath(input.cwd, input.host);
192
+ if (!fs.existsSync(targetPath)) {
193
+ return null;
194
+ }
195
+ const cachedContent = fs.readFileSync(targetPath, 'utf8');
196
+ const content = [
197
+ '---',
198
+ 'nativesoul: bootstrap-context-cache',
199
+ `host: ${input.host}`,
200
+ `generated_at: ${new Date().toISOString()}`,
201
+ 'degraded: true',
202
+ 'warnings: PROJECT_BOOTSTRAP_CACHE_FALLBACK',
203
+ '---',
204
+ '',
205
+ cachedContent
206
+ ].join('\n');
207
+ return {
208
+ content,
209
+ degraded: true,
210
+ warnings: ['PROJECT_BOOTSTRAP_CACHE_FALLBACK'],
211
+ source: 'nativesoul-project-cache',
212
+ targetPath
213
+ };
214
+ } catch {
215
+ return null;
216
+ }
217
+ }
218
+
219
+ function parseJsonStdout(result) {
220
+ if (result.status !== 0 || !result.stdout.trim()) {
221
+ return null;
222
+ }
223
+ try {
224
+ return JSON.parse(result.stdout);
225
+ } catch {
226
+ return null;
227
+ }
228
+ }
229
+
230
+ function buildPreToolUseHookOutput(result) {
231
+ if (!result || result.blocked !== true) {
232
+ return null;
233
+ }
234
+ return {
235
+ decision: 'block',
236
+ reason: result.message,
237
+ blocked: true,
238
+ hookSpecificOutput: {
239
+ hookEventName: 'PreToolUse',
240
+ permissionDecision: 'deny',
241
+ permissionDecisionReason: result.message
242
+ },
243
+ nativeSoulPolicy: result
244
+ };
245
+ }
246
+
247
+ function runNonBlocking(main, timeoutMs = DEFAULT_HOOK_TIMEOUT_MS) {
248
+ const timer = setTimeout(() => {
249
+ process.exit(0);
250
+ }, timeoutMs + 1000);
251
+ timer.unref();
252
+ main()
253
+ .then(() => {
254
+ clearTimeout(timer);
255
+ process.exitCode = 0;
256
+ })
257
+ .catch(() => {
258
+ clearTimeout(timer);
259
+ process.exitCode = 0;
260
+ });
261
+ }
262
+
263
+ module.exports = {
264
+ DEFAULT_HOOK_TIMEOUT_MS,
265
+ appendHomeArg,
266
+ buildPreToolUseHookOutput,
267
+ claudeDesktopConfigPath,
268
+ defaultMcpConfigCandidates,
269
+ parseJsonStdout,
270
+ projectBootstrapCachePath,
271
+ projectFallbackBootstrapHome,
272
+ readStdin,
273
+ readProjectFallbackCache,
274
+ resolveNativeSoulCli,
275
+ resolveProjectDir,
276
+ runNonBlocking,
277
+ spawnNativeSoul,
278
+ writeProjectFallbackCache
279
+ };