wispy-cli 2.7.15 → 2.7.16

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/bin/wispy.mjs CHANGED
@@ -757,12 +757,31 @@ if (command === "exec") {
757
757
  const disallowedTools = globalDisallowedTools || null;
758
758
  const agent = globalAgent || null;
759
759
 
760
+ // Load project settings and merge
761
+ const { findProjectSettings, mergeSettings } = await import(join(rootDir, "core/project-settings.mjs"));
762
+ const projectSettings = await findProjectSettings();
763
+ const mergedConfig = mergeSettings(
764
+ profileConfig,
765
+ projectSettings,
766
+ null, // profile already merged into profileConfig via loadConfigWithProfile
767
+ {
768
+ ...(personality ? { personality } : {}),
769
+ ...(effort ? { effort } : {}),
770
+ ...(maxBudgetUsd ? { maxBudgetUsd } : {}),
771
+ ...(globalSystemPrompt ? { systemPrompt: globalSystemPrompt } : {}),
772
+ ...(globalAppendSystemPrompt ? { appendSystemPrompt: globalAppendSystemPrompt } : {}),
773
+ }
774
+ );
775
+
760
776
  const engine = new WispyEngine({
761
- personality,
762
- effort,
763
- maxBudgetUsd,
764
- allowedTools,
765
- disallowedTools,
777
+ ...mergedConfig,
778
+ personality: mergedConfig.personality ?? personality,
779
+ effort: mergedConfig.effort ?? effort,
780
+ maxBudgetUsd: mergedConfig.maxBudgetUsd ?? maxBudgetUsd,
781
+ allowedTools: mergedConfig.allowedTools ?? allowedTools,
782
+ disallowedTools: mergedConfig.disallowedTools ?? disallowedTools,
783
+ systemPrompt: mergedConfig.systemPrompt ?? null,
784
+ appendSystemPrompt: mergedConfig.appendSystemPrompt ?? null,
766
785
  workstream: process.env.WISPY_WORKSTREAM ?? "default",
767
786
  });
768
787
 
@@ -789,6 +808,7 @@ if (command === "exec") {
789
808
  personality,
790
809
  effort,
791
810
  agent,
811
+ sessionName: globalSessionName ?? null,
792
812
  skipSkillCapture: true,
793
813
  skipUserModel: true,
794
814
  });
@@ -976,7 +996,8 @@ if (command === "sessions") {
976
996
  for (const s of sessions) {
977
997
  const ts = new Date(s.updatedAt).toLocaleString();
978
998
  const preview = s.firstMessage ? ` "${s.firstMessage.slice(0, 60)}${s.firstMessage.length > 60 ? "…" : ""}"` : "";
979
- console.log(` ${s.id}`);
999
+ const nameLabel = s.name ? ` · 📎 ${s.name}` : "";
1000
+ console.log(` ${s.id}${nameLabel}`);
980
1001
  console.log(` ${ts} · ${s.workstream} · ${s.messageCount} msgs${s.model ? ` · ${s.model}` : ""}`);
981
1002
  if (preview) console.log(` ${preview}`);
982
1003
  console.log("");
@@ -987,7 +1008,7 @@ if (command === "sessions") {
987
1008
  const choices = [
988
1009
  { name: "(exit)", value: null },
989
1010
  ...sessions.map(s => ({
990
- name: `${s.id} ${new Date(s.updatedAt).toLocaleString()} "${(s.firstMessage ?? "").slice(0, 50)}"`,
1011
+ name: `${s.id}${s.name ? ` [${s.name}]` : ""} ${new Date(s.updatedAt).toLocaleString()} "${(s.firstMessage ?? "").slice(0, 50)}"`,
991
1012
  value: s.id,
992
1013
  })),
993
1014
  ];
@@ -1056,7 +1077,7 @@ if (command === "resume") {
1056
1077
  }
1057
1078
 
1058
1079
  const choices = sessions.map(s => ({
1059
- name: `${new Date(s.updatedAt).toLocaleString()} [${s.workstream}] ${s.messageCount}msgs "${(s.firstMessage ?? "").slice(0, 50)}"`,
1080
+ name: `${new Date(s.updatedAt).toLocaleString()} [${s.workstream}]${s.name ? ` 📎 ${s.name}` : ""} ${s.messageCount}msgs "${(s.firstMessage ?? "").slice(0, 50)}"`,
1060
1081
  value: s.id,
1061
1082
  }));
1062
1083
 
@@ -1105,7 +1126,7 @@ if (command === "fork") {
1105
1126
  }
1106
1127
 
1107
1128
  const choices = sessions.map(s => ({
1108
- name: `${new Date(s.updatedAt).toLocaleString()} [${s.workstream}] ${s.messageCount}msgs "${(s.firstMessage ?? "").slice(0, 50)}"`,
1129
+ name: `${new Date(s.updatedAt).toLocaleString()} [${s.workstream}]${s.name ? ` 📎 ${s.name}` : ""} ${s.messageCount}msgs "${(s.firstMessage ?? "").slice(0, 50)}"`,
1109
1130
  value: s.id,
1110
1131
  }));
1111
1132
 
package/core/engine.mjs CHANGED
@@ -102,6 +102,12 @@ export class WispyEngine {
102
102
  ?? "default";
103
103
  // Personality: from config, or null (use default Wispy personality)
104
104
  this._personality = config.personality ?? null;
105
+ // System prompt overrides from config
106
+ this._systemPrompt = config.systemPrompt ?? null; // full replacement
107
+ this._appendSystemPrompt = config.appendSystemPrompt ?? null; // append to default
108
+ // Project settings cache (loaded lazily)
109
+ this._projectSettings = null;
110
+ this._projectSettingsLoaded = false;
105
111
  // Agent manager
106
112
  this.agentManager = new AgentManager(config);
107
113
  // Effort level: low | medium | high | max
@@ -327,6 +327,7 @@ ${bold("Wispy Commands:")}
327
327
  ${cyan("/search")} <keyword> Search across workstreams
328
328
  ${cyan("/skills")} List installed skills
329
329
  ${cyan("/sessions")} List sessions
330
+ ${cyan("/name")} <name> Give this session a display name (e.g. /name refactor-auth)
330
331
  ${cyan("/mcp")} [list|connect|disconnect|config|reload] MCP management
331
332
  ${cyan("/remember")} <text> Save text to main memory (MEMORY.md)
332
333
  ${cyan("/forget")} <key> Delete a memory file
@@ -1069,6 +1070,28 @@ ${bold("Permissions & Audit (v1.1):")}
1069
1070
  return true;
1070
1071
  }
1071
1072
 
1073
+ if (cmd.startsWith("/name")) {
1074
+ const nameParts = input.split(" ").slice(1);
1075
+ const sessionName = nameParts.join(" ").trim();
1076
+ if (!sessionName) {
1077
+ console.log(yellow("Usage: /name <display-name> (e.g. /name refactor-auth)"));
1078
+ return true;
1079
+ }
1080
+ // Find the active session and set its name
1081
+ try {
1082
+ const currentSession = engine.sessions?.list?.()?.find(Boolean);
1083
+ if (currentSession) {
1084
+ await engine.sessions.setName(currentSession.id, sessionName);
1085
+ console.log(green(`📎 Session named: "${sessionName}" (${currentSession.id})`));
1086
+ } else {
1087
+ console.log(yellow("No active session found."));
1088
+ }
1089
+ } catch (err) {
1090
+ console.log(red(`Failed to set session name: ${err.message}`));
1091
+ }
1092
+ return true;
1093
+ }
1094
+
1072
1095
  if (cmd === "/quit" || cmd === "/exit") {
1073
1096
  console.log(dim(`🌿 Bye! (${engine.providers.formatCost()})`));
1074
1097
  engine.destroy();
@@ -1293,6 +1316,7 @@ async function runRepl(engine) {
1293
1316
  noSave: true,
1294
1317
  dryRun: engine.dryRunMode ?? false,
1295
1318
  images: pendingImages,
1319
+ sessionName: process.env.WISPY_SESSION_NAME ?? null,
1296
1320
  onSkillLearned: (skill) => {
1297
1321
  console.log(cyan(`\n💡 Learned new skill: '${skill.name}' — use /${skill.name} next time`));
1298
1322
  },
@@ -1476,8 +1500,29 @@ if (args[0] && operatorCommands.has(args[0])) {
1476
1500
  process.exit(0);
1477
1501
  }
1478
1502
 
1479
- // Initialize engine
1480
- const engine = new WispyEngine({ workstream: ACTIVE_WORKSTREAM });
1503
+ // Initialize engine — merge project settings + env flags
1504
+ let _engineConfig = { workstream: ACTIVE_WORKSTREAM };
1505
+ try {
1506
+ const { findProjectSettings, mergeSettings } = await import("../core/project-settings.mjs");
1507
+ const { loadConfigWithProfile } = await import("../core/config.mjs");
1508
+ const projectSettings = await findProjectSettings();
1509
+ if (projectSettings) {
1510
+ const baseConfig = await loadConfigWithProfile(process.env.WISPY_PROFILE ?? null);
1511
+ _engineConfig = mergeSettings(baseConfig, projectSettings, null, {
1512
+ ...(process.env.WISPY_SYSTEM_PROMPT ? { systemPrompt: process.env.WISPY_SYSTEM_PROMPT } : {}),
1513
+ ...(process.env.WISPY_APPEND_SYSTEM_PROMPT ? { appendSystemPrompt: process.env.WISPY_APPEND_SYSTEM_PROMPT } : {}),
1514
+ ...(process.env.WISPY_EFFORT ? { effort: process.env.WISPY_EFFORT } : {}),
1515
+ });
1516
+ _engineConfig.workstream = _engineConfig.workstream ?? ACTIVE_WORKSTREAM;
1517
+ } else {
1518
+ // No project settings, still pick up env flags
1519
+ if (process.env.WISPY_SYSTEM_PROMPT) _engineConfig.systemPrompt = process.env.WISPY_SYSTEM_PROMPT;
1520
+ if (process.env.WISPY_APPEND_SYSTEM_PROMPT) _engineConfig.appendSystemPrompt = process.env.WISPY_APPEND_SYSTEM_PROMPT;
1521
+ if (process.env.WISPY_EFFORT) _engineConfig.effort = process.env.WISPY_EFFORT;
1522
+ }
1523
+ } catch { /* project settings are optional */ }
1524
+
1525
+ const engine = new WispyEngine(_engineConfig);
1481
1526
  const initResult = await engine.init();
1482
1527
 
1483
1528
  if (!initResult) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wispy-cli",
3
- "version": "2.7.15",
3
+ "version": "2.7.16",
4
4
  "description": "🌿 Wispy — AI workspace assistant with trustworthy execution (harness, receipts, approvals, diffs)",
5
5
  "license": "MIT",
6
6
  "author": "Minseo & Poropo",