@lamemind/loom-deck 0.75.0 → 0.77.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.
- package/README.md +24 -2
- package/dist/actions.js +67 -5
- package/dist/archivable.js +1 -1
- package/dist/claude-cmd.js +101 -0
- package/dist/cli.js +18 -7
- package/dist/commit-times.js +5 -2
- package/dist/config.js +51 -6
- package/dist/deck-model.js +14 -9
- package/dist/deck-run.js +7 -0
- package/dist/doc-tree.js +2 -2
- package/dist/frame.js +7 -0
- package/dist/git-bash.js +78 -0
- package/dist/gitlink.js +1 -0
- package/dist/hooks.js +21 -7
- package/dist/inbox.js +2 -2
- package/dist/input.js +7 -0
- package/dist/live-sessions.js +4 -1
- package/dist/overlays/gitlink.js +12 -2
- package/dist/overlays/wrap.js +10 -1
- package/dist/pane-views.js +12 -2
- package/dist/platform.js +93 -0
- package/dist/project-path.js +102 -0
- package/dist/purge.js +1 -0
- package/dist/sane-note.js +18 -24
- package/dist/sessions.js +63 -29
- package/dist/spawn-catalog.js +4 -4
- package/dist/spawn-config.js +4 -4
- package/dist/spawn.js +77 -11
- package/dist/tab-args.js +141 -0
- package/dist/tab-compose.js +233 -0
- package/dist/tab-launch.js +169 -0
- package/dist/tab-wrapper.js +44 -0
- package/dist/tasks.js +9 -22
- package/dist/ui/doc-pane.js +6 -2
- package/dist/ui/inbox-pane.js +7 -2
- package/dist/windows-terminal.js +153 -0
- package/dist/wrap-scan.js +2 -2
- package/package.json +3 -2
- package/scripts/deck-run +11 -678
- package/scripts/prompt-catalog +6 -11
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// T176 — le tab di WINDOWS TERMINAL: argv di `wt.exe`, env della tab, il canale
|
|
2
|
+
// che porta l'argv di `claude` al wrapper.
|
|
3
|
+
//
|
|
4
|
+
// Su Windows una conversazione si apre con
|
|
5
|
+
//
|
|
6
|
+
// wt.exe -w 0 new-tab -p loom-deck -d <root> --title <titolo>
|
|
7
|
+
// --suppressApplicationTitle -- <node> <tab-wrapper.js>
|
|
8
|
+
//
|
|
9
|
+
// e l'argv di `claude` (nome, flag, prompt) NON sta su quella riga: viaggia come
|
|
10
|
+
// JSON nella variabile `LOOM_DECK_TAB_ARGV`, perché la tab eredita l'env del
|
|
11
|
+
// processo che lancia `wt.exe` (T174 verdetto 5, rimisurato con `-p`). Il
|
|
12
|
+
// wrapper la legge, la toglie e lancia `claude` senza shell (P3 preflight).
|
|
13
|
+
// Così il prompt non passa né dal parser di `wt` né da una shell: `wt` legge `;`
|
|
14
|
+
// come separatore di sottocomandi in QUALUNQUE argomento, anche dopo `--` e
|
|
15
|
+
// anche escapato `\;` (misurato su Windows Terminal 1.24: la coda dopo il `;`
|
|
16
|
+
// diventa una tab a sé, col proprio errore), e cmd o PowerShell
|
|
17
|
+
// interpreterebbero `' " & % ^ |`.
|
|
18
|
+
//
|
|
19
|
+
// Modulo PURO: l'env arriva come valore, il bash di Git come stringa già
|
|
20
|
+
// risolta.
|
|
21
|
+
/** Il lanciatore di Windows Terminal: l'alias d'esecuzione in `WindowsApps`,
|
|
22
|
+
* che `spawn` trova nel `PATH` e lancia senza shell (misurato). */
|
|
23
|
+
export const WT_CMD = 'wt.exe';
|
|
24
|
+
/** Il profilo delle tab del deck (P9 preflight): uno solo per tutti i
|
|
25
|
+
* progetti, nascosto dal menu, creato a mano dall'utente nel `settings.json` di
|
|
26
|
+
* Windows Terminal. Porta ciò che i flag non dicono — font, `closeOnExit`, la
|
|
27
|
+
* shell del tasto `t`; titolo, cartella e comando li passa il deck. */
|
|
28
|
+
export const WT_PROFILE_DEFAULT = 'loom-deck';
|
|
29
|
+
/** La variabile con cui l'argv di `claude` arriva al wrapper della tab. */
|
|
30
|
+
export const TAB_ARGV_ENV = 'LOOM_DECK_TAB_ARGV';
|
|
31
|
+
/**
|
|
32
|
+
* I marker che una sessione Claude Code inietta nei processi figli (P4
|
|
33
|
+
* preflight, misurati nella shell di una sessione su Windows).
|
|
34
|
+
*
|
|
35
|
+
* La tab eredita tutto l'env del deck, e un deck avviato da una shell aperta
|
|
36
|
+
* dentro Claude Code li porterebbe nella conversazione nuova: con
|
|
37
|
+
* `CLAUDE_CODE_CHILD_SESSION` la sessione non salva il transcript («Transcript
|
|
38
|
+
* saving is off — inherited CLAUDE_CODE_CHILD_SESSION marker») e non compare
|
|
39
|
+
* nello storico del deck. Lista chiusa e non ogni `CLAUDE*`: un
|
|
40
|
+
* `CLAUDE_CONFIG_DIR` o un `CLAUDE_CODE_GIT_BASH_PATH` dell'utente sparirebbero
|
|
41
|
+
* senza segnale, mentre un marker nuovo di una versione futura si annuncia da
|
|
42
|
+
* sé, nel messaggio di avvio di `claude` che lo nomina.
|
|
43
|
+
*/
|
|
44
|
+
export const SESSION_MARKERS = [
|
|
45
|
+
'CLAUDECODE',
|
|
46
|
+
'CLAUDE_CODE_CHILD_SESSION',
|
|
47
|
+
'CLAUDE_CODE_SESSION_ID',
|
|
48
|
+
'CLAUDE_PID',
|
|
49
|
+
'CLAUDE_EFFORT',
|
|
50
|
+
'CLAUDE_CODE_MESSAGING_SOCKET',
|
|
51
|
+
'CLAUDE_CODE_MESSAGING_TOKEN',
|
|
52
|
+
'CLAUDE_CODE_ENTRYPOINT',
|
|
53
|
+
'CLAUDE_CODE_SESSION_ATTENDED',
|
|
54
|
+
'CLAUDE_CODE_EXECPATH',
|
|
55
|
+
];
|
|
56
|
+
const GIT_BASH_ENV = 'CLAUDE_CODE_GIT_BASH_PATH';
|
|
57
|
+
/** Il profilo da passare a `-p`: `LOOM_DECK_WT_PROFILE` se impostata (vuota =
|
|
58
|
+
* nessun `-p`, il profilo di default di Windows Terminal), altrimenti
|
|
59
|
+
* `loom-deck`. Un profilo che non esiste non è un errore: Windows Terminal
|
|
60
|
+
* apre la tab col profilo di default e non dice niente (misurato), quindi il
|
|
61
|
+
* deck lo passa sempre senza verificarlo. */
|
|
62
|
+
export function wtProfile(env) {
|
|
63
|
+
const v = env.LOOM_DECK_WT_PROFILE;
|
|
64
|
+
if (v === undefined)
|
|
65
|
+
return WT_PROFILE_DEFAULT;
|
|
66
|
+
return v || null;
|
|
67
|
+
}
|
|
68
|
+
/** Il titolo come lo riceve `wt`: senza `;`, che spezzerebbe il comando. Il
|
|
69
|
+
* titolo è composto dal deck (label, TaskID, nota ridotta) e un `;` può
|
|
70
|
+
* venire solo dal nome del progetto: si toglie invece di fallire. */
|
|
71
|
+
export function wtTitle(title) {
|
|
72
|
+
return title.replace(/;/g, '');
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* L'argv di `wt.exe` per una tab nuova.
|
|
76
|
+
*
|
|
77
|
+
* `-w 0` è la finestra di Windows Terminal usata per ultima — quella da cui si
|
|
78
|
+
* lavora col deck —, `-w new` una finestra nuova (l'equivalente di
|
|
79
|
+
* `--new-window` di Ptyxis). `--suppressApplicationTitle` tiene il titolo del
|
|
80
|
+
* deck contro quello che il programma della tab imposta (misurato): è ciò che su
|
|
81
|
+
* Linux fa `-T` di Ptyxis contro l'OSC del prompt. Senza titolo il flag non si
|
|
82
|
+
* passa, e la tab prende quello della shell.
|
|
83
|
+
*/
|
|
84
|
+
export function wtNewTabArgs(tab) {
|
|
85
|
+
const args = ['-w', tab.newWindow ? 'new' : '0', 'new-tab'];
|
|
86
|
+
if (tab.profile)
|
|
87
|
+
args.push('-p', tab.profile);
|
|
88
|
+
args.push('-d', tab.cwd);
|
|
89
|
+
if (tab.title !== null)
|
|
90
|
+
args.push('--title', wtTitle(tab.title), '--suppressApplicationTitle');
|
|
91
|
+
if (tab.command)
|
|
92
|
+
args.push('--', ...tab.command);
|
|
93
|
+
return args;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Il primo argomento di `wt` che contiene un `;`, o `null`.
|
|
97
|
+
*
|
|
98
|
+
* Il titolo è già ripulito; restano i path (la cartella, node, il wrapper) e il
|
|
99
|
+
* nome del profilo. Un path col `;` è legale su NTFS e `wt` non lo sa portare:
|
|
100
|
+
* lo spawn si ferma dicendolo, invece di aprire una tab d'errore con metà
|
|
101
|
+
* comando.
|
|
102
|
+
*/
|
|
103
|
+
export function semicolonArg(args) {
|
|
104
|
+
return args.find((a) => a.includes(';')) ?? null;
|
|
105
|
+
}
|
|
106
|
+
/** Toglie una chiave ignorando le maiuscole: su Windows l'env non le distingue,
|
|
107
|
+
* e una copia di `process.env` può portare `Path` invece di `PATH`. */
|
|
108
|
+
function deleteKey(env, key) {
|
|
109
|
+
const want = key.toUpperCase();
|
|
110
|
+
for (const k of Object.keys(env))
|
|
111
|
+
if (k.toUpperCase() === want)
|
|
112
|
+
delete env[k];
|
|
113
|
+
}
|
|
114
|
+
function hasKey(env, key) {
|
|
115
|
+
const want = key.toUpperCase();
|
|
116
|
+
return Object.keys(env).some((k) => k.toUpperCase() === want && env[k]);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* L'env di una tab aperta dal deck su Windows: quello del deck, meno i marker di
|
|
120
|
+
* sessione, con la task della conversazione e il bash di Git.
|
|
121
|
+
*
|
|
122
|
+
* `task` = `null` per le tab senza task (`--no-task`, il tasto `t`): una
|
|
123
|
+
* `LOOM_TASK` ereditata legherebbe a una task una sessione che non ne ha, e
|
|
124
|
+
* l'hook `SessionStart` ne inietterebbe il task file. `CLAUDE_CODE_GIT_BASH_PATH`
|
|
125
|
+
* entra quando manca e il bash si trova: la tab eredita anche il `PATH`, e col
|
|
126
|
+
* `PATH` di Git Bash `claude` eseguirebbe gli hook del plugin in PowerShell
|
|
127
|
+
* (T174 verdetto 9), cioè senza la task in contesto.
|
|
128
|
+
*/
|
|
129
|
+
export function windowsTabEnv(env, task, gitBash) {
|
|
130
|
+
const out = { ...env };
|
|
131
|
+
for (const marker of SESSION_MARKERS)
|
|
132
|
+
deleteKey(out, marker);
|
|
133
|
+
deleteKey(out, 'LOOM_TASK');
|
|
134
|
+
deleteKey(out, TAB_ARGV_ENV);
|
|
135
|
+
if (task)
|
|
136
|
+
out.LOOM_TASK = task;
|
|
137
|
+
if (gitBash && !hasKey(env, GIT_BASH_ENV))
|
|
138
|
+
out[GIT_BASH_ENV] = gitBash;
|
|
139
|
+
return out;
|
|
140
|
+
}
|
|
141
|
+
/** L'argv di `claude` letto dalla variabile della tab, o `null` se manca o non
|
|
142
|
+
* è un array di stringhe. */
|
|
143
|
+
export function parseTabArgv(raw) {
|
|
144
|
+
if (!raw)
|
|
145
|
+
return null;
|
|
146
|
+
try {
|
|
147
|
+
const v = JSON.parse(raw);
|
|
148
|
+
return Array.isArray(v) && v.every((a) => typeof a === 'string') ? v : null;
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
}
|
package/dist/wrap-scan.js
CHANGED
|
@@ -87,7 +87,7 @@ export const WRAP_DEFAULT_PATH = '.';
|
|
|
87
87
|
* T161 — il buco `{path}` del titolo e del prompt di una sessione di
|
|
88
88
|
* srotolamento: il path reso a parole.
|
|
89
89
|
*
|
|
90
|
-
* Le barre diventano spazi e l'estensione cade QUI, prima di `
|
|
90
|
+
* Le barre diventano spazi e l'estensione cade QUI, prima di `saneNote`, il
|
|
91
91
|
* cui alfabeto non ha né `/` né `.`: lasciandoceli cadere le parole si
|
|
92
92
|
* salderebbero (`runtimereferencedoc-systemmd`), e il titolo della tab
|
|
93
93
|
* divergerebbe da quello che la lista del deck legge dal sidecar.
|
|
@@ -145,7 +145,7 @@ export async function runWrapScan(projectRoot) {
|
|
|
145
145
|
if (!script)
|
|
146
146
|
return false;
|
|
147
147
|
try {
|
|
148
|
-
const { stdout } = await execFileAsync('python3', [script, '--root', projectRoot, '--scan'], { cwd: projectRoot, maxBuffer: 16 * 1024 * 1024 });
|
|
148
|
+
const { stdout } = await execFileAsync('python3', [script, '--root', projectRoot, '--scan'], { cwd: projectRoot, maxBuffer: 16 * 1024 * 1024, windowsHide: true });
|
|
149
149
|
const path = wrapCacheFile(projectRoot);
|
|
150
150
|
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
151
151
|
writeFileSync(path, stdout, { mode: 0o600 });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lamemind/loom-deck",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.77.0",
|
|
4
4
|
"description": "Deck TUI Ink per-progetto della famiglia loom: legge tasks.md e spawna sessioni Claude Code bound via LOOM_TASK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"scripts": {
|
|
14
14
|
"dev": "tsx src/cli.tsx",
|
|
15
15
|
"build": "tsc",
|
|
16
|
-
"
|
|
16
|
+
"pretest": "tsc",
|
|
17
|
+
"test": "node test/run.mjs",
|
|
17
18
|
"start": "node dist/cli.js",
|
|
18
19
|
"prepare": "tsc"
|
|
19
20
|
},
|