agentlas 1.0.38 → 1.0.39

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.39 — 2026-08-11
4
+
5
+ pi-tui shell increment 2 + architecture mirror sync.
6
+
7
+ - Experimental pi shell (`AGENTLAS_TUI=pi`): persisted history (cli-history.json
8
+ v2 contract), Shift-Tab permission cycling (same two-step FULL arming state
9
+ machine as the classic REPL), `!` shell passthrough (full-permission gate,
10
+ secret masking), and `/s` `/switch` `/kill` `/rm` `/sessions` `/tree` session
11
+ observation wired to the same orchestrator/renderer pair.
12
+ - Streaming display masks the Memory Events envelope (runtime contract, not
13
+ user-facing text); the harvest pipeline is unchanged.
14
+ - ARCHITECTURE_VERSION mirror synced 1.7.0 → 1.7.1 (vendor regenerated from
15
+ the desktop dist, value-level parity gate green).
16
+
3
17
  ## 1.0.38 — 2026-08-11
4
18
 
5
19
  Silence was the worst failure mode — this release makes failures speak.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.7.0",
2
+ "version": "1.7.1",
3
3
  "emitterBlock": "## Memory (Agentlas curated memory)\n\nAt the end of EVERY completed normal reply, emit exactly one hidden Memory Events\nenvelope. The runtime removes it before display. This envelope is the per-turn receipt:\nalways include a compact safe turn_summary, and use an empty candidates array when\nnothing durable was learned. Do not skip the envelope.\n\nRules:\n- Never include secrets, credentials, API keys, raw logs, or full transcripts.\n- Real credential values may live only in local project .env/.env.local,\n ignored signing/ or credentials/ files, or a local keychain/vault. Memory\n Events may mention env names and local relative paths only.\n- For deploy, release, store, billing, auth, API, or cloud work, first read the\n project's .agentlas/local-credentials.map.json and the top\n \"Local Credential Index\" section of .agentlas/project-soul-memory.md\n before saying a credential is missing.\n- One candidate per durable item. Keep \"content\" to one or two sentences.\n- \"memory_kind\": fact | decision | preference | risk | procedure | hypothesis | evidence | deprecation | conflict\n- \"suggested_scope\": user_identity | team_memory | project (this folder) | agent_repo | session (temporary) | discard\n- Use user_identity for a stable operator preference or personal fact (their name, role, language, tone,\n how they want you to behave) — these must outlive any one project. The curator only files user_identity\n when you label it so with \"confidence\": \"high\"; it never promotes into that scope, so a preference emitted\n at lower confidence is demoted to a throwaway session note.\n- \"agent_team\" is accepted only as a legacy alias for team_memory.\n- Add \"request_context\" when it improves future recall: user_intent, trigger_terms,\n cwd_at_request, target_project, target_path, cross_context, outcome.\n- Never put the raw user prompt or transcript in request_context.\n- Suggest a scope; the separate Memory Curator decides the final destination.\n- turn_summary is one value-free sentence about the completed outcome. It is not the\n user prompt, a transcript, raw log, secret, or absolute local path.\n\nFormat (always emit, including an empty candidates array):\n\n## Memory Events\n```json\n{\n \"schema_version\": \"agentlas.memory-ticket.v1\",\n \"turn_summary\": \"Completed outcome in one safe sentence.\",\n \"candidates\": [\n {\n \"memory_kind\": \"decision\",\n \"content\": \"...\",\n \"suggested_scope\": \"project\",\n \"confidence\": \"high\",\n \"sensitivity\": \"internal\",\n \"evidence_refs\": [],\n \"request_context\": {\n \"user_intent\": \"...\",\n \"trigger_terms\": [\"...\"],\n \"cwd_at_request\": null,\n \"target_project\": null,\n \"target_path\": null,\n \"cross_context\": false,\n \"outcome\": \"...\"\n }\n }\n ]\n}\n```",
4
4
  "eventsHeading": "## Memory Events",
5
5
  "memoryDir": ".agentlas",
@@ -202,6 +202,26 @@ async function startPiShell(ctx, opts = {}) {
202
202
  const editor = new pi.Editor(tui, editorTheme, { autocompleteMaxVisible: 8 });
203
203
  editor.setAutocompleteProvider(new pi.CombinedAutocompleteProvider(toSlashCommands(ctx.lang), process.cwd()));
204
204
 
205
+ // ── 히스토리 디스크 영속 (증분 2) — cli-history.json v2 계약을 그대로 재사용 ──
206
+ const input = require("../agentlas-input.cjs");
207
+ const historyLedger = (() => { try { return input.loadHistory(process.cwd()); } catch { return []; } })();
208
+ // readline 히스토리는 최신-우선 배열 — Editor에는 과거→최신 순으로 먹인다.
209
+ for (const entry of [...historyLedger].reverse()) editor.addToHistory(entry);
210
+ const recordHistory = (line) => {
211
+ historyLedger.unshift(line);
212
+ if (historyLedger.length > input.HISTORY_MAX) historyLedger.length = input.HISTORY_MAX;
213
+ try { input.saveHistory(historyLedger, process.cwd()); } catch { /* 히스토리는 최선노력 */ }
214
+ };
215
+
216
+ // ── Shift-Tab 권한 순환 (증분 2) — repl의 순수 상태기계를 그대로 재사용 ──
217
+ const { createPermissionShortcut } = require("./repl.cjs");
218
+ const permShortcut = createPermissionShortcut({
219
+ lang: ctx.lang,
220
+ getPermission: () => permission,
221
+ setPermission: (level) => { permission = level; },
222
+ onMessage: (msg) => { ui.ensureNl(); ui.line(ui.c.dim(msg.text)); },
223
+ });
224
+
205
225
  const commands = require("../commands/index.cjs");
206
226
  const handleSlash = async (cmdline) => {
207
227
  const raw = cmdline.split(/\s+/)[0] || "";
@@ -212,6 +232,26 @@ async function startPiShell(ctx, opts = {}) {
212
232
  ui.line(palette.renderPalette(ctx.lang));
213
233
  return;
214
234
  }
235
+ // 세션 관찰/전환 (증분 2b) — 기본 REPL과 같은 orch/renderer 배선
236
+ if (cmd === "sessions" || cmd === "tree") {
237
+ require("./repl.cjs").printSessions(shellCtx, orch);
238
+ return;
239
+ }
240
+ if (cmd === "s" || cmd === "switch" || cmd === "kill" || cmd === "rm") {
241
+ const token = rest[0];
242
+ if (!token) { ui.line(ui.c.dim(`Usage: /${cmd} <n>`)); return; }
243
+ const key = String(token).startsWith("s") ? token : `s${token}`;
244
+ if (cmd === "kill") { orch.kill(key); return; }
245
+ if (cmd === "rm") {
246
+ orch.remove(key);
247
+ const act = orch.active();
248
+ if (act) renderer.attach(act, { replay: false });
249
+ return;
250
+ }
251
+ const session = orch.setActive(key);
252
+ renderer.attach(session, { replay: true });
253
+ return;
254
+ }
215
255
  const EXCLUDED = new Set(["firm", "setup", "run"]);
216
256
  if (!EXCLUDED.has(cmd) && commands.COMMANDS[cmd]) {
217
257
  await commands.COMMANDS[cmd]().run(shellCtx, rest);
@@ -229,10 +269,16 @@ async function startPiShell(ctx, opts = {}) {
229
269
  const input = String(text || "").trim();
230
270
  if (!input) return;
231
271
  editor.addToHistory(input);
272
+ recordHistory(input);
232
273
  editor.setText("");
233
274
  ui.ensureNl();
234
275
  ui.line(ui.c.emerald("› ") + ui.c.text(input));
235
276
  (async () => {
277
+ if (input.startsWith("!")) {
278
+ await require("./repl.cjs").runShell(shellCtx, input.slice(1).trim(), permission)
279
+ .catch((e) => { if (e && (e.code || e.honestStop)) ui.error(e); else ui.error(); });
280
+ return;
281
+ }
236
282
  if (input.startsWith("/")) {
237
283
  const verdict = await handleSlash(input.slice(1)).catch((e) => {
238
284
  if (e && (e.code || e.honestStop)) ui.error(e);
@@ -265,6 +311,13 @@ async function startPiShell(ctx, opts = {}) {
265
311
  };
266
312
 
267
313
  tui.addInputListener((data) => {
314
+ // Shift-Tab 권한 순환 — pi-tui 가 raw mode 를 단독 소유하므로 readline 의
315
+ // swallowCompletion 우회 없이 여기서 직접 소비한다 (D2 위험 2의 해소 형태).
316
+ if (pi.matchesKey(data, "shift+tab")) {
317
+ permShortcut.handleKey("", { name: "tab", shift: true });
318
+ return { handled: true };
319
+ }
320
+ if (permShortcut.armed()) permShortcut.handleKey("", { name: "other" }); // 다른 키 = 무장 해제
268
321
  if (pi.matchesKey(data, "ctrl+c")) {
269
322
  const active = orch.active();
270
323
  if (active && active.isBusy()) {
@@ -786,4 +786,4 @@ function handleSlash(ctx, cmdline, api) {
786
786
  }
787
787
  }
788
788
 
789
- module.exports = { startRepl, printSessions, createPermissionShortcut };
789
+ module.exports = { startRepl, printSessions, createPermissionShortcut, runShell };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentlas",
3
- "version": "1.0.38",
3
+ "version": "1.0.39",
4
4
  "description": "Agentlas project terminal — run project controllers and task-scoped agent teams from the terminal. Standalone: no desktop app process required.",
5
5
  "bin": {
6
6
  "agentlas": "bin/agentlas.cjs"