iranti 0.2.24 → 0.2.25

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.
@@ -3824,6 +3824,18 @@ async function setupCommand(args) {
3824
3824
  let result = null;
3825
3825
  await withPromptSession(async (prompt) => {
3826
3826
  let setupMode = 'isolated';
3827
+ printChoiceGuide('Runtime Mode Choices', [
3828
+ {
3829
+ choice: 'isolated',
3830
+ meaning: 'one project gets its own runtime root and usually its own instance boundary',
3831
+ useWhen: 'one repo should stay self-contained and you do not want other repos sharing its memory/runtime by default.',
3832
+ },
3833
+ {
3834
+ choice: 'shared',
3835
+ meaning: 'multiple projects can bind to the same runtime root and instances under it',
3836
+ useWhen: 'several repos should intentionally share one Iranti instance and memory space.',
3837
+ },
3838
+ ]);
3827
3839
  while (true) {
3828
3840
  const chosen = (await prompt.line('Runtime mode (isolated or shared)', 'isolated') ?? 'isolated').trim().toLowerCase();
3829
3841
  if (chosen === 'shared' || chosen === 'isolated') {
@@ -3835,10 +3847,20 @@ async function setupCommand(args) {
3835
3847
  let finalScope = 'user';
3836
3848
  let finalRoot = '';
3837
3849
  if (setupMode === 'isolated') {
3850
+ printWizardNotes('Isolated Runtime Path', [
3851
+ 'This folder becomes the runtime root for this isolated setup.',
3852
+ 'Iranti stores instance env files, runtime metadata, logs, and install metadata under this root.',
3853
+ 'Use a project-local path like `<repo>/.iranti-runtime` when one repo should own its own runtime.',
3854
+ ]);
3838
3855
  finalRoot = path_1.default.resolve(await promptNonEmpty(prompt, 'Isolated runtime path', explicitRoot ?? path_1.default.join(process.cwd(), '.iranti-runtime')));
3839
3856
  finalScope = 'user';
3840
3857
  }
3841
3858
  else {
3859
+ printWizardNotes('Shared Runtime Scope', [
3860
+ 'Shared mode uses one runtime root that can hold multiple named instances.',
3861
+ 'Choose `user` for a per-user machine install. Choose `system` only when you deliberately want a machine-wide shared location.',
3862
+ 'Use `--root` instead when you need an exact custom shared runtime path.',
3863
+ ]);
3842
3864
  while (true) {
3843
3865
  const chosenScope = (await prompt.line('Install scope (user or system)', explicitScope ?? 'user') ?? 'user').trim().toLowerCase();
3844
3866
  if (chosenScope === 'user' || chosenScope === 'system') {
@@ -3875,6 +3897,23 @@ async function setupCommand(args) {
3875
3897
  let databaseProvisioned = false;
3876
3898
  let dockerContainerName;
3877
3899
  let databaseMode = recommendedDatabaseMode;
3900
+ printChoiceGuide('Database Mode Choices', [
3901
+ {
3902
+ choice: 'local',
3903
+ meaning: 'use PostgreSQL already running on this machine',
3904
+ useWhen: 'you already have local Postgres with pgvector, or want Iranti to reuse a local developer database.',
3905
+ },
3906
+ {
3907
+ choice: 'docker',
3908
+ meaning: 'start or reuse a local PostgreSQL container just for the database',
3909
+ useWhen: 'you want a reliable local pgvector path without managing a direct host Postgres install.',
3910
+ },
3911
+ {
3912
+ choice: 'managed',
3913
+ meaning: 'use a remote PostgreSQL connection string you already control',
3914
+ useWhen: 'your database lives on Railway, Supabase, Neon, or another hosted PostgreSQL service.',
3915
+ },
3916
+ ]);
3878
3917
  while (true) {
3879
3918
  const defaultMode = recommendedDatabaseMode;
3880
3919
  const dbMode = (await prompt.line('Database mode (local, managed, or docker)', defaultMode) ?? defaultMode).trim().toLowerCase();
@@ -3929,6 +3968,23 @@ async function setupCommand(args) {
3929
3968
  console.log(`${warnLabel()} Choose one of: local, managed, docker.`);
3930
3969
  }
3931
3970
  let provider = normalizeProvider(existingInstance?.env.LLM_PROVIDER ?? 'openai') ?? 'openai';
3971
+ printChoiceGuide('Provider Choices', [
3972
+ {
3973
+ choice: 'mock',
3974
+ meaning: 'local development provider with no remote API key requirement',
3975
+ useWhen: 'you want to validate setup and runtime behavior before spending money on a remote model provider.',
3976
+ },
3977
+ {
3978
+ choice: 'openai / claude / gemini / groq / mistral',
3979
+ meaning: 'remote hosted model providers that need an upstream API key',
3980
+ useWhen: 'you want real model-backed Iranti behavior and already have a provider key.',
3981
+ },
3982
+ {
3983
+ choice: 'ollama',
3984
+ meaning: 'local Ollama runtime instead of a hosted provider',
3985
+ useWhen: 'you want local model execution and already run Ollama on the machine.',
3986
+ },
3987
+ ]);
3932
3988
  while (true) {
3933
3989
  listProviderChoices(provider, existingInstance?.env ?? {});
3934
3990
  const chosen = normalizeProvider(await promptNonEmpty(prompt, 'Default LLM provider', provider));
@@ -3987,10 +4043,20 @@ async function setupCommand(args) {
3987
4043
  }
3988
4044
  const projects = [];
3989
4045
  const defaultProjectPath = process.cwd();
4046
+ printWizardNotes('Project Binding', [
4047
+ 'Binding a project writes `.env.iranti` into one specific repo or app folder.',
4048
+ 'Use the project root that should contain the binding file, not a broad parent folder like your whole `Projects` directory.',
4049
+ 'In shared mode you can bind multiple repos to the same instance. In isolated mode you normally bind one repo.',
4050
+ ]);
3990
4051
  let shouldBindProject = await promptYesNo(prompt, 'Bind a project folder to this instance now?', true);
3991
4052
  while (shouldBindProject) {
3992
4053
  const projectPath = path_1.default.resolve(await promptNonEmpty(prompt, 'Project path to bind', projects.length === 0 ? defaultProjectPath : process.cwd()));
3993
4054
  const agentId = sanitizeIdentifier(await promptNonEmpty(prompt, 'Project agent ID', projectAgentDefault(projectPath)), 'project_main');
4055
+ printWizardNotes('Project Memory Entity', [
4056
+ 'This is the durable memory namespace the project will use by default.',
4057
+ 'Use a stable entity like `project/my_repo` when the repo should have its own long-lived shared memory identity.',
4058
+ 'Use a narrower entity only when you intentionally want this project bound to some other memory namespace.',
4059
+ ]);
3994
4060
  const memoryEntity = await promptNonEmpty(prompt, 'Project memory entity', 'user/main');
3995
4061
  const claudeCode = await promptYesNo(prompt, 'Create Claude Code project files here now?', true);
3996
4062
  projects.push({
@@ -4007,6 +4073,13 @@ async function setupCommand(args) {
4007
4073
  shouldBindProject = false;
4008
4074
  }
4009
4075
  }
4076
+ if (projects.length > 0 && hasCodexInstalled()) {
4077
+ printWizardNotes('Codex Registration', [
4078
+ 'This registers Iranti with the global Codex CLI MCP config.',
4079
+ 'Say yes when this machine should let Codex call Iranti tools from bound projects.',
4080
+ 'Say no if you are not using Codex yet or do not want to touch the global Codex config right now.',
4081
+ ]);
4082
+ }
4010
4083
  const codex = projects.length > 0 && hasCodexInstalled()
4011
4084
  ? await promptYesNo(prompt, 'Register Codex globally for the first bound project now?', false)
4012
4085
  : false;
@@ -4901,6 +4974,13 @@ async function configureInstanceCommand(args) {
4901
4974
  let clearProviderKey = hasFlag(args, 'clear-provider-key');
4902
4975
  if (hasFlag(args, 'interactive')) {
4903
4976
  await withPromptSession(async (prompt) => {
4977
+ printWizardNotes('Interactive Instance Configuration', [
4978
+ 'This updates one existing instance in place.',
4979
+ 'API port controls where the Iranti API listens.',
4980
+ 'DATABASE_URL points at the PostgreSQL database for this instance.',
4981
+ 'LLM provider and provider key control which model backend Iranti uses.',
4982
+ 'Iranti API key is the client credential other tools and project bindings use to authenticate.',
4983
+ ]);
4904
4984
  portRaw = await prompt.line('API port', portRaw ?? env.IRANTI_PORT);
4905
4985
  dbUrl = await prompt.line('DATABASE_URL', dbUrl ?? env.DATABASE_URL);
4906
4986
  providerInput = await prompt.line('LLM provider', providerInput ?? env.LLM_PROVIDER ?? 'mock');
@@ -5004,6 +5084,14 @@ async function configureProjectCommand(args) {
5004
5084
  let explicitProjectMode = getFlag(args, 'mode');
5005
5085
  if (hasFlag(args, 'interactive')) {
5006
5086
  await withPromptSession(async (prompt) => {
5087
+ printWizardNotes('Interactive Project Configuration', [
5088
+ 'This updates the `.env.iranti` binding inside one project folder.',
5089
+ 'Instance name retargets the binding to a named local instance and derives URL/env metadata from it.',
5090
+ 'Iranti URL and Project API key are the direct connection details the project will use.',
5091
+ 'Project agent ID is the default agent identity for tools running from this repo.',
5092
+ 'Project memory entity is the durable namespace the project will use for shared memory.',
5093
+ 'Project mode should stay `isolated` for repo-local memory or `shared` only when this repo should intentionally share one instance with other repos.',
5094
+ ]);
5007
5095
  instanceName = await prompt.line('Instance name', instanceName);
5008
5096
  explicitUrl = await prompt.line('Iranti URL', explicitUrl ?? existing.IRANTI_URL);
5009
5097
  explicitApiKey = await prompt.secret('Project API key', explicitApiKey ?? existing.IRANTI_API_KEY);
@@ -5638,6 +5726,22 @@ function printOptionGuide(title, entries) {
5638
5726
  }
5639
5727
  console.log('');
5640
5728
  }
5729
+ function printChoiceGuide(title, entries) {
5730
+ console.log(sectionTitle(title));
5731
+ for (const entry of entries) {
5732
+ console.log(` ${commandText(entry.choice)}`);
5733
+ console.log(` What it means: ${entry.meaning}`);
5734
+ console.log(` Use this when: ${entry.useWhen}`);
5735
+ }
5736
+ console.log('');
5737
+ }
5738
+ function printWizardNotes(title, lines) {
5739
+ console.log(sectionTitle(title));
5740
+ for (const line of lines) {
5741
+ console.log(` - ${line}`);
5742
+ }
5743
+ console.log('');
5744
+ }
5641
5745
  function printHelp() {
5642
5746
  const rows = [
5643
5747
  {
@@ -144,7 +144,7 @@ async function main() {
144
144
  await ensureDefaultAgent(iranti);
145
145
  const server = new mcp_js_1.McpServer({
146
146
  name: 'iranti-mcp',
147
- version: '0.2.24',
147
+ version: '0.2.25',
148
148
  });
149
149
  server.registerTool('iranti_handshake', {
150
150
  description: `Initialize or refresh an agent's working-memory brief for the current task.
@@ -41,7 +41,7 @@ const INSTANCE_DIR = process.env.IRANTI_INSTANCE_DIR?.trim()
41
41
  const INSTANCE_RUNTIME_FILE = process.env.IRANTI_INSTANCE_RUNTIME_FILE?.trim()
42
42
  || (INSTANCE_DIR ? (0, runtimeLifecycle_1.runtimeFileForInstance)(INSTANCE_DIR) : null);
43
43
  const INSTANCE_NAME = process.env.IRANTI_INSTANCE_NAME?.trim() || (INSTANCE_DIR ? path_1.default.basename(INSTANCE_DIR) : 'adhoc');
44
- const VERSION = '0.2.24';
44
+ const VERSION = '0.2.25';
45
45
  // M-18: Warn at startup if API key pepper is not set (important for production security)
46
46
  if (!process.env.IRANTI_API_KEY_PEPPER) {
47
47
  console.warn('[security] WARNING: IRANTI_API_KEY_PEPPER is not set. API key hashes have no pepper — set this env var in production.');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iranti",
3
- "version": "0.2.24",
3
+ "version": "0.2.25",
4
4
  "description": "Memory infrastructure for multi-agent AI systems",
5
5
  "main": "dist/src/sdk/index.js",
6
6
  "files": [