[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

This commit is contained in:
2026-09-13 18:24:01 +08:00
commit 3c72efcb7f
3255 changed files with 907009 additions and 0 deletions

View File

@@ -0,0 +1,232 @@
import type { Monaco } from '@monaco-editor/react';
type CompletionDisposable = { dispose: () => void };
const NCT_API_COMPLETIONS = [
{
label: 'nct.screen.waitForPrompt',
sortText: 'nct.screen.waitFor.00.prompt',
insertText: 'await nct.screen.waitForPrompt(${1:30000});',
detail: 'Wait for shell prompt',
documentation: 'Wait until an interactive shell prompt appears (# for root, $ for regular user).',
},
{
label: 'nct.screen.waitForText',
sortText: 'nct.screen.waitFor.01.text',
insertText: "await nct.screen.waitForText('${1:text}', ${2:30000});",
detail: 'Wait for literal text',
documentation: 'Wait until the exact text appears in session output. Regex characters are treated as normal text.',
},
{
label: 'nct.screen.waitForRegex',
sortText: 'nct.screen.waitFor.02.regex',
insertText: "await nct.screen.waitForRegex('${1:pattern}', ${2:30000});",
detail: 'Wait for regex match',
documentation: 'Wait until session output matches a regular expression. String patterns use dotAll matching for multiline output.',
},
{
label: 'nct.screen.waitFor',
sortText: 'nct.screen.waitFor.03.legacy',
insertText: "await nct.screen.waitFor('${1:text}', ${2:30000});",
detail: 'Wait for terminal output (legacy)',
documentation: 'Compatibility helper. Plain string patterns are literal; legacy /regex/flags strings still work, but prefer waitForText for text or waitForRegex for regular expressions.',
},
{
label: 'nct.screen.waitForAny',
insertText: "await nct.screen.waitForAny(['# ', '$ ', '~# ', '~$ '], ${1:30000});",
detail: 'Wait for any pattern',
documentation: 'Wait until any of the given patterns appears in session output.',
},
{
label: 'nct.screen.sendLine',
insertText: "await nct.screen.sendLine('${1:command}');",
detail: 'Send line + Enter',
documentation: 'Send text to the terminal followed by carriage return.',
},
{
label: 'nct.screen.send',
insertText: "await nct.screen.send('${1:text}');",
detail: 'Send text',
documentation: 'Send text to the terminal without pressing Enter.',
},
{
label: 'nct.screen.getText',
insertText: 'const output = await nct.screen.getText();',
detail: 'Read terminal text',
documentation: 'Read visible terminal buffer text or a row range.',
},
{
label: 'nct.screen.clear',
insertText: 'await nct.screen.clear();',
detail: 'Clear terminal screen',
documentation: 'Send a clear-screen sequence to the terminal.',
},
{
label: 'nct.session.sleep',
insertText: 'await nct.session.sleep(${1:1000});',
detail: 'Pause script',
documentation: 'Pause script execution for the given milliseconds.',
},
{
label: 'nct.sleep',
insertText: 'await nct.sleep(${1:1000});',
detail: 'Pause script',
documentation: 'Alias for nct.session.sleep.',
},
{
label: 'nct.session.startLog',
insertText: "await nct.session.startLog('${1:./script.log}');",
detail: 'Start session log',
documentation: 'Start writing session output to a local log file.',
},
{
label: 'nct.session.stopLog',
insertText: 'await nct.session.stopLog();',
detail: 'Stop session log',
documentation: 'Stop the active script log stream.',
},
{
label: 'nct.session.disconnect',
insertText: 'await nct.session.disconnect();',
detail: 'Disconnect session',
documentation: 'Close the current terminal session.',
},
{
label: 'nct.dialog.confirm',
insertText: "const ok = await nct.dialog.confirm('${1:Continue?}');",
detail: 'Confirm dialog',
documentation: 'Show a confirm dialog and return true when accepted.',
},
{
label: 'nct.dialog.prompt',
insertText: "const value = await nct.dialog.prompt('${1:Input}', '${2:}');",
detail: 'Prompt dialog',
documentation: 'Show an input dialog and return the entered string.',
},
{
label: 'nct.dialog.alert',
insertText: "await nct.dialog.alert('${1:Message}');",
detail: 'Alert dialog',
documentation: 'Show an informational alert dialog.',
},
{
label: 'nct.dialog.form',
insertText: [
'const values = await nct.dialog.form({',
" title: '${1:Options}',",
" message: '${2:Choose how to continue}',",
' fields: [',
" { type: 'select', name: '${3:env}', label: '${4:Environment}', options: ['${5:dev}', '${6:prod}'], defaultValue: '${5:dev}' },",
" { type: 'checkbox', name: '${7:restart}', label: '${8:Restart service}', defaultValue: true },",
" { type: 'textarea', name: '${9:notes}', label: '${10:Notes}', required: false, visibleWhen: { field: '${3:env}', notEquals: '${5:dev}' } },",
" { type: 'number', name: '${11:retries}', label: '${12:Retries}', defaultValue: 3, min: 0, step: 1 },",
' ],',
'});',
].join('\n'),
detail: 'Form dialog',
documentation: 'Show a form dialog with select, checkbox, radio, textarea, and number fields. Fields can use visibleWhen for conditional display. Returns an object keyed by visible field name.',
},
{
label: 'nct.dialog.select',
insertText: "const value = await nct.dialog.select('${1:Choose one}', ['${2:first}', '${3:second}'], '${2:first}');",
detail: 'Select dialog',
documentation: 'Show a single-select dialog and return the selected option value.',
},
{
label: 'nct.dialog.radio',
insertText: "const value = await nct.dialog.radio('${1:Choose one}', ['${2:first}', '${3:second}'], '${2:first}');",
detail: 'Radio dialog',
documentation: 'Show a radio-choice dialog and return the selected option value.',
},
{
label: 'nct.dialog.checkbox',
insertText: "const checked = await nct.dialog.checkbox('${1:Enable option}', ${2:true});",
detail: 'Checkbox dialog',
documentation: 'Show a checkbox dialog and return whether it is checked.',
},
{
label: 'nct.log',
insertText: "nct.log('${1:message}');",
detail: 'Script log',
documentation: 'Append a line to the script run log panel.',
},
{
label: 'nct.progress.start',
insertText: "nct.progress.start('${1:Phase name}', ${2:total});",
detail: 'Start determinate progress',
documentation: 'Opt in to a labeled X/Y progress bar for known-length loops.',
},
{
label: 'nct.progress.step',
insertText: "nct.progress.step('${1:detail}');",
detail: 'Advance progress',
documentation: 'Increment determinate progress by one step.',
},
{
label: 'nct.progress.set',
insertText: "nct.progress.set(${1:current}, '${2:detail}');",
detail: 'Set progress position',
documentation: 'Set determinate progress to a specific index.',
},
{
label: 'nct.progress.done',
insertText: 'nct.progress.done();',
detail: 'Finish progress phase',
documentation: 'Complete the current determinate progress phase.',
},
];
let registered = false;
let disposable: CompletionDisposable | null = null;
export function registerNctMonacoCompletionProvider(monaco: Monaco): CompletionDisposable {
if (registered && disposable) {
return disposable;
}
disposable = monaco.languages.registerCompletionItemProvider('javascript', {
triggerCharacters: ['.', '('],
provideCompletionItems: (model, position) => {
const word = model.getWordUntilPosition(position);
const range = {
startLineNumber: position.lineNumber,
endLineNumber: position.lineNumber,
startColumn: word.startColumn,
endColumn: word.endColumn,
};
const prefix = model.getValueInRange({
startLineNumber: position.lineNumber,
startColumn: 1,
endLineNumber: position.lineNumber,
endColumn: position.column,
});
const suggestions = NCT_API_COMPLETIONS
.filter((item) => {
if (prefix.trim().length === 0) return true;
return item.label.startsWith('nct') && prefix.includes('nct');
})
.map((item) => ({
label: item.label,
kind: monaco.languages.CompletionItemKind.Method,
insertText: item.insertText,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
detail: item.detail,
documentation: item.documentation,
sortText: item.sortText ?? item.label,
range,
}));
return { suggestions };
},
});
registered = true;
return disposable;
}
export function disposeNctMonacoCompletionProvider() {
disposable?.dispose();
disposable = null;
registered = false;
}

View File

@@ -0,0 +1,35 @@
export type ScreenSnapshotProvider = () => {
rows: number;
cols: number;
currentRow: number;
lines: string[];
/** Optional origin marker (e.g. hibernate-viewport). */
source?: string;
};
const providers = new Map<string, ScreenSnapshotProvider>();
export function registerScreenSnapshotProvider(
sessionId: string,
provider: ScreenSnapshotProvider,
): () => void {
providers.set(sessionId, provider);
return () => {
if (providers.get(sessionId) === provider) {
providers.delete(sessionId);
}
};
}
export function captureScreenSnapshot(sessionId: string) {
const provider = providers.get(sessionId);
if (!provider) {
return {
rows: 24,
cols: 80,
currentRow: 0,
lines: [] as string[],
};
}
return provider();
}