[Init] Initial commit - NetMesh terminal manager
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
This commit is contained in:
181
domain/snippetScript.ts
Normal file
181
domain/snippetScript.ts
Normal file
@@ -0,0 +1,181 @@
|
||||
import type { Snippet, SnippetKind } from './models';
|
||||
|
||||
export function getSnippetKind(snippet: Pick<Snippet, 'kind'>): SnippetKind {
|
||||
return snippet.kind === 'script' ? 'script' : 'snippet';
|
||||
}
|
||||
|
||||
export function isScriptSnippet(snippet: Pick<Snippet, 'kind'>): boolean {
|
||||
return getSnippetKind(snippet) === 'script';
|
||||
}
|
||||
|
||||
/** Common interactive shell prompts (root uses #, regular user uses $). */
|
||||
export const DEFAULT_SHELL_PROMPT_PATTERNS = ['# ', '$ ', '~# ', '~$ ', '% '];
|
||||
|
||||
/** Default wait after each recorded command — matches waitForPrompt in generated scripts. */
|
||||
export const DEFAULT_RECORDING_PROMPT_TIMEOUT_MS = 30000;
|
||||
|
||||
/** Regex matching a shell prompt on the last line (~# / ~$ / user@host:path#). */
|
||||
export const SHELL_PROMPT_END_REGEX = /(?:~[#$]\s*|[@][^\n]{0,120}[:][^\n]{0,120}[#$%]\s*)$/m;
|
||||
|
||||
/** Minimal smoke script for verifying manual run and onOutput triggers. */
|
||||
export const SCRIPT_SMOKE_TEST = `// === Smoke test ===
|
||||
// Manual: trigger=manual, pick a target host, click "Run now"
|
||||
// onOutput: trigger=onOutput, pattern=NETCATTY_SMOKE, save, connect to target host, then run: echo NETCATTY_SMOKE
|
||||
//
|
||||
await nct.screen.waitForPrompt(30000);
|
||||
await nct.screen.sendLine('echo netcatty-smoke-ok');
|
||||
nct.log('Smoke test passed');
|
||||
await nct.dialog.alert('Netcatty script smoke test OK');
|
||||
`;
|
||||
|
||||
/** Full integration test for onConnect / manual run; dialog API enabled by default. */
|
||||
export const SCRIPT_INTEGRATION_TEST = `// Netcatty Integration Test — onConnect / manual full API exercise
|
||||
// Trigger: onConnect or Run now | Permission: Auto or Confirm (dialogs need non-Observer)
|
||||
|
||||
const CONFIG = {
|
||||
SAMPLE_COUNT: 8,
|
||||
SAMPLE_INTERVAL_MS: 2000,
|
||||
PROMPT_TIMEOUT_MS: 60000,
|
||||
STEP_TIMEOUT_MS: 20000,
|
||||
RUN_DIALOGS: true,
|
||||
RUN_SESSION_LOG: false,
|
||||
RUN_SCREEN_CLEAR: false,
|
||||
};
|
||||
|
||||
async function main() {
|
||||
const tag = \`nc-it-\${Date.now().toString(36)}\`;
|
||||
nct.log('=== Netcatty Integration Test START ===');
|
||||
nct.log(\`tag=\${tag} nct.version=\${nct.version}\`);
|
||||
nct.log(\`session: name=\${nct.session.name} host=\${nct.session.hostname} user=\${nct.session.username} connected=\${nct.session.connected}\`);
|
||||
|
||||
if (!nct.session.connected) {
|
||||
throw new Error('Session not connected');
|
||||
}
|
||||
|
||||
nct.log('[1/12] waitForPrompt');
|
||||
await nct.screen.waitForPrompt(CONFIG.PROMPT_TIMEOUT_MS);
|
||||
|
||||
nct.log('[2/12] sendLine + waitForText');
|
||||
await nct.screen.sendLine(\`echo "\${tag}_BOOTSTRAP_OK"\`);
|
||||
await nct.screen.waitForText(\`\${tag}_BOOTSTRAP_OK\`, CONFIG.STEP_TIMEOUT_MS);
|
||||
|
||||
nct.log('[3/12] waitForAny');
|
||||
await nct.screen.sendLine('echo ANY_CHECK && uname -s');
|
||||
await nct.screen.waitForAny(['ANY_CHECK', /Linux/], CONFIG.STEP_TIMEOUT_MS);
|
||||
|
||||
nct.log('[4/12] getText / rows / cols / currentRow');
|
||||
const text = await nct.screen.getText();
|
||||
const lineCount = text.split('\\n').filter(Boolean).length;
|
||||
nct.log(\`captured \${lineCount} lines, rows=\${nct.screen.rows} cols=\${nct.screen.cols} cursorRow=\${nct.screen.currentRow}\`);
|
||||
|
||||
nct.log('[5/12] send raw + Enter');
|
||||
await nct.screen.send(\`echo -n "\${tag}_RAW"\`);
|
||||
await nct.screen.sendLine('');
|
||||
await nct.screen.waitForText(\`\${tag}_RAW\`, CONFIG.STEP_TIMEOUT_MS);
|
||||
|
||||
nct.log('[6/12] waitForRegex');
|
||||
await nct.screen.sendLine(\`echo BUILD_ID=\${tag}\`);
|
||||
await nct.screen.waitForRegex(new RegExp(\`BUILD_ID=\${tag}\`), CONFIG.STEP_TIMEOUT_MS);
|
||||
|
||||
nct.log('[7/12] session.sleep / nct.sleep');
|
||||
await nct.session.sleep(800);
|
||||
await nct.sleep(800);
|
||||
|
||||
nct.log('[8/12] progress loop health sampling');
|
||||
nct.progress.start('Health sampling', CONFIG.SAMPLE_COUNT);
|
||||
for (let i = 1; i <= CONFIG.SAMPLE_COUNT; i += 1) {
|
||||
const cmd = [
|
||||
\`echo "== Sample \${i}/\${CONFIG.SAMPLE_COUNT} =="\`,
|
||||
'date',
|
||||
'uptime',
|
||||
"free -h | awk 'NR==2{print $1,$2,$3,$4,$7}'",
|
||||
"df -h / | awk 'NR==2{print $1,$2,$3,$5,$6}'",
|
||||
\`echo "\${tag}_SAMPLE_\${i}_DONE"\`,
|
||||
].join(' && ');
|
||||
await nct.screen.sendLine(cmd);
|
||||
await nct.screen.waitForRegex(new RegExp(\`\${tag}_SAMPLE_\${i}_DONE\`), CONFIG.STEP_TIMEOUT_MS);
|
||||
await nct.screen.waitForPrompt(CONFIG.PROMPT_TIMEOUT_MS);
|
||||
nct.progress.step(\`sample \${i}/\${CONFIG.SAMPLE_COUNT}\`);
|
||||
nct.log(\`sample \${i}/\${CONFIG.SAMPLE_COUNT} ok\`);
|
||||
if (i < CONFIG.SAMPLE_COUNT) {
|
||||
await nct.session.sleep(CONFIG.SAMPLE_INTERVAL_MS);
|
||||
}
|
||||
}
|
||||
nct.progress.done();
|
||||
|
||||
nct.log('[9/12] nested loop activity mode');
|
||||
const checks = ['whoami', 'id -u', 'pwd', 'echo $SHELL'];
|
||||
for (const check of checks) {
|
||||
await nct.screen.sendLine(check);
|
||||
await nct.screen.waitForPrompt(CONFIG.PROMPT_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
if (CONFIG.RUN_SESSION_LOG) {
|
||||
nct.log('[10/12] startLog / stopLog');
|
||||
await nct.session.startLog(\`./netcatty-it-\${tag}.log\`);
|
||||
await nct.screen.sendLine(\`echo "\${tag}_LOGGED"\`);
|
||||
await nct.screen.waitForText(\`\${tag}_LOGGED\`, CONFIG.STEP_TIMEOUT_MS);
|
||||
await nct.session.stopLog();
|
||||
} else {
|
||||
nct.log('[10/12] startLog/stopLog skipped');
|
||||
}
|
||||
|
||||
if (CONFIG.RUN_SCREEN_CLEAR) {
|
||||
nct.log('[11/12] screen.clear');
|
||||
await nct.screen.clear();
|
||||
await nct.session.sleep(500);
|
||||
await nct.screen.waitForPrompt(CONFIG.PROMPT_TIMEOUT_MS);
|
||||
} else {
|
||||
nct.log('[11/12] screen.clear skipped');
|
||||
}
|
||||
|
||||
if (CONFIG.RUN_DIALOGS) {
|
||||
nct.log('[12/12] dialog confirm / prompt / alert');
|
||||
const go = await nct.dialog.confirm(\`Integration test \${tag} finished OK. Continue to prompt/alert?\`);
|
||||
nct.log(\`confirm => \${go}\`);
|
||||
if (go) {
|
||||
const note = await nct.dialog.prompt('Optional note:', 'all-good');
|
||||
nct.log(\`prompt => \${note}\`);
|
||||
await nct.dialog.alert(\`Done. note=\${note}\`);
|
||||
} else {
|
||||
nct.log('confirm declined — skipping prompt/alert');
|
||||
}
|
||||
} else {
|
||||
nct.log('[12/12] dialog skipped');
|
||||
}
|
||||
|
||||
await nct.screen.sendLine(\`echo "=== \${tag} ALL_PASSED ==="\`);
|
||||
await nct.screen.waitForText(\`\${tag} ALL_PASSED\`, CONFIG.STEP_TIMEOUT_MS);
|
||||
nct.log('=== Netcatty Integration Test PASSED ===');
|
||||
}
|
||||
|
||||
await main();
|
||||
`;
|
||||
|
||||
export const DEFAULT_SCRIPT_TEMPLATE = `// Netcatty automation script - async JS in the active terminal session
|
||||
//
|
||||
// nct.screen.waitForPrompt(ms?) wait for shell prompt (# root / $ user)
|
||||
// nct.screen.waitForText(text, ms?) wait for exact output text
|
||||
// nct.screen.waitForRegex(pattern, ms?) wait for regex output, including multiline
|
||||
// nct.screen.waitForAny([patterns], ms?) wait until any pattern matches
|
||||
// nct.screen.sendLine(cmd) type command + Enter; send(text) raw keys only
|
||||
// nct.screen.getText(start?, end?) | clear()
|
||||
// nct.session.connected | name | hostname | username (read-only metadata)
|
||||
// nct.session.sleep(ms) | startLog(path) | stopLog() | disconnect()
|
||||
// nct.dialog.confirm(msg)->bool | prompt(msg, def?)->string | alert(msg)
|
||||
// nct.dialog.form({ fields })->object; fields: select/radio/checkbox/textarea/number, optional visibleWhen
|
||||
// nct.dialog.select/radio/checkbox are convenience helpers
|
||||
// nct.progress.start(label, total) opt-in determinate progress for loops
|
||||
// nct.progress.step(detail?) | set(n, detail?) | done()
|
||||
// nct.log(msg) run log panel. Type "nct." in editor for autocomplete snippets.
|
||||
//
|
||||
await nct.screen.waitForPrompt(30000);
|
||||
await nct.screen.sendLine('echo hello');
|
||||
nct.log('Done');
|
||||
`;
|
||||
|
||||
const SCRIPT_WRITE_PATTERN = /nct\.screen\.(send(?:Line)?|clear)\s*\(|nct\.session\.(disconnect|startLog)\s*\(/;
|
||||
|
||||
export function scriptContainsWriteOperations(content: string): boolean {
|
||||
return SCRIPT_WRITE_PATTERN.test(String(content || ''));
|
||||
}
|
||||
Reference in New Issue
Block a user