@link-assistant/agent 0.5.0 → 0.5.1
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/package.json +1 -1
- package/src/index.js +249 -209
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -673,97 +673,253 @@ async function main() {
|
|
|
673
673
|
.command(McpCommand)
|
|
674
674
|
// Auth subcommand
|
|
675
675
|
.command(AuthCommand)
|
|
676
|
-
// Default
|
|
677
|
-
.
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
676
|
+
// Default command for agent mode (when no subcommand specified)
|
|
677
|
+
.command({
|
|
678
|
+
command: '$0',
|
|
679
|
+
describe: 'Run agent in interactive or stdin mode (default)',
|
|
680
|
+
builder: (yargs) =>
|
|
681
|
+
yargs
|
|
682
|
+
.option('model', {
|
|
683
|
+
type: 'string',
|
|
684
|
+
description: 'Model to use in format providerID/modelID',
|
|
685
|
+
default: 'opencode/grok-code',
|
|
686
|
+
})
|
|
687
|
+
.option('json-standard', {
|
|
688
|
+
type: 'string',
|
|
689
|
+
description:
|
|
690
|
+
'JSON output format standard: "opencode" (default) or "claude" (experimental)',
|
|
691
|
+
default: 'opencode',
|
|
692
|
+
choices: ['opencode', 'claude'],
|
|
693
|
+
})
|
|
694
|
+
.option('system-message', {
|
|
695
|
+
type: 'string',
|
|
696
|
+
description: 'Full override of the system message',
|
|
697
|
+
})
|
|
698
|
+
.option('system-message-file', {
|
|
699
|
+
type: 'string',
|
|
700
|
+
description: 'Full override of the system message from file',
|
|
701
|
+
})
|
|
702
|
+
.option('append-system-message', {
|
|
703
|
+
type: 'string',
|
|
704
|
+
description: 'Append to the default system message',
|
|
705
|
+
})
|
|
706
|
+
.option('append-system-message-file', {
|
|
707
|
+
type: 'string',
|
|
708
|
+
description: 'Append to the default system message from file',
|
|
709
|
+
})
|
|
710
|
+
.option('server', {
|
|
711
|
+
type: 'boolean',
|
|
712
|
+
description: 'Run in server mode (default)',
|
|
713
|
+
default: true,
|
|
714
|
+
})
|
|
715
|
+
.option('verbose', {
|
|
716
|
+
type: 'boolean',
|
|
717
|
+
description:
|
|
718
|
+
'Enable verbose mode to debug API requests (shows system prompt, token counts, etc.)',
|
|
719
|
+
default: false,
|
|
720
|
+
})
|
|
721
|
+
.option('dry-run', {
|
|
722
|
+
type: 'boolean',
|
|
723
|
+
description:
|
|
724
|
+
'Simulate operations without making actual API calls or package installations (useful for testing)',
|
|
725
|
+
default: false,
|
|
726
|
+
})
|
|
727
|
+
.option('use-existing-claude-oauth', {
|
|
728
|
+
type: 'boolean',
|
|
729
|
+
description:
|
|
730
|
+
'Use existing Claude OAuth credentials from ~/.claude/.credentials.json (from Claude Code CLI)',
|
|
731
|
+
default: false,
|
|
732
|
+
})
|
|
733
|
+
.option('prompt', {
|
|
734
|
+
alias: 'p',
|
|
735
|
+
type: 'string',
|
|
736
|
+
description:
|
|
737
|
+
'Prompt message to send directly (bypasses stdin reading)',
|
|
738
|
+
})
|
|
739
|
+
.option('disable-stdin', {
|
|
740
|
+
type: 'boolean',
|
|
741
|
+
description:
|
|
742
|
+
'Disable stdin streaming mode (requires --prompt or shows help)',
|
|
743
|
+
default: false,
|
|
744
|
+
})
|
|
745
|
+
.option('stdin-stream-timeout', {
|
|
746
|
+
type: 'number',
|
|
747
|
+
description:
|
|
748
|
+
'Optional timeout in milliseconds for stdin reading (default: no timeout)',
|
|
749
|
+
})
|
|
750
|
+
.option('auto-merge-queued-messages', {
|
|
751
|
+
type: 'boolean',
|
|
752
|
+
description:
|
|
753
|
+
'Enable auto-merging of rapidly arriving input lines into single messages (default: true)',
|
|
754
|
+
default: true,
|
|
755
|
+
})
|
|
756
|
+
.option('interactive', {
|
|
757
|
+
type: 'boolean',
|
|
758
|
+
description:
|
|
759
|
+
'Enable interactive mode to accept manual input as plain text strings (default: true). Use --no-interactive to only accept JSON input.',
|
|
760
|
+
default: true,
|
|
761
|
+
})
|
|
762
|
+
.option('always-accept-stdin', {
|
|
763
|
+
type: 'boolean',
|
|
764
|
+
description:
|
|
765
|
+
'Keep accepting stdin input even after the agent finishes work (default: true). Use --no-always-accept-stdin for single-message mode.',
|
|
766
|
+
default: true,
|
|
767
|
+
})
|
|
768
|
+
.option('compact-json', {
|
|
769
|
+
type: 'boolean',
|
|
770
|
+
description:
|
|
771
|
+
'Output compact JSON (single line) instead of pretty-printed JSON (default: false). Useful for program-to-program communication.',
|
|
772
|
+
default: false,
|
|
773
|
+
}),
|
|
774
|
+
handler: async (argv) => {
|
|
775
|
+
const compactJson = argv['compact-json'] === true;
|
|
776
|
+
|
|
777
|
+
// Check if --prompt flag was provided
|
|
778
|
+
if (argv.prompt) {
|
|
779
|
+
// Direct prompt mode - bypass stdin entirely
|
|
780
|
+
const request = { message: argv.prompt };
|
|
781
|
+
await runAgentMode(argv, request);
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// Check if --disable-stdin was set without --prompt
|
|
786
|
+
if (argv['disable-stdin']) {
|
|
787
|
+
// Output a helpful message suggesting to use --prompt
|
|
788
|
+
outputStatus(
|
|
789
|
+
{
|
|
790
|
+
type: 'error',
|
|
791
|
+
message:
|
|
792
|
+
'No prompt provided. Use -p/--prompt to specify a message, or remove --disable-stdin to read from stdin.',
|
|
793
|
+
hint: 'Example: agent -p "Hello, how are you?"',
|
|
794
|
+
},
|
|
795
|
+
compactJson
|
|
796
|
+
);
|
|
797
|
+
process.exit(1);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// Check if stdin is a TTY (interactive terminal)
|
|
801
|
+
if (process.stdin.isTTY) {
|
|
802
|
+
// Enter interactive terminal mode with continuous listening
|
|
803
|
+
const isInteractive = argv.interactive !== false;
|
|
804
|
+
const autoMerge = argv['auto-merge-queued-messages'] !== false;
|
|
805
|
+
const alwaysAcceptStdin = argv['always-accept-stdin'] !== false;
|
|
806
|
+
|
|
807
|
+
// Exit if --no-always-accept-stdin is set (single message mode not supported in TTY)
|
|
808
|
+
if (!alwaysAcceptStdin) {
|
|
809
|
+
outputStatus(
|
|
810
|
+
{
|
|
811
|
+
type: 'error',
|
|
812
|
+
message:
|
|
813
|
+
'Single message mode (--no-always-accept-stdin) is not supported in interactive terminal mode.',
|
|
814
|
+
hint: 'Use piped input or --prompt for single messages.',
|
|
815
|
+
},
|
|
816
|
+
compactJson
|
|
817
|
+
);
|
|
818
|
+
process.exit(1);
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
outputStatus(
|
|
822
|
+
{
|
|
823
|
+
type: 'status',
|
|
824
|
+
mode: 'interactive-terminal',
|
|
825
|
+
message:
|
|
826
|
+
'Agent CLI in interactive terminal mode. Type your message and press Enter.',
|
|
827
|
+
hint: 'Press CTRL+C to exit. Use --help for options.',
|
|
828
|
+
acceptedFormats: isInteractive
|
|
829
|
+
? ['JSON object with "message" field', 'Plain text']
|
|
830
|
+
: ['JSON object with "message" field'],
|
|
831
|
+
options: {
|
|
832
|
+
interactive: isInteractive,
|
|
833
|
+
autoMergeQueuedMessages: autoMerge,
|
|
834
|
+
alwaysAcceptStdin,
|
|
835
|
+
compactJson,
|
|
836
|
+
},
|
|
837
|
+
},
|
|
838
|
+
compactJson
|
|
839
|
+
);
|
|
840
|
+
|
|
841
|
+
// Use continuous mode for interactive terminal
|
|
842
|
+
await runContinuousAgentMode(argv);
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// stdin is piped - enter stdin listening mode
|
|
847
|
+
const isInteractive = argv.interactive !== false;
|
|
848
|
+
const autoMerge = argv['auto-merge-queued-messages'] !== false;
|
|
849
|
+
const alwaysAcceptStdin = argv['always-accept-stdin'] !== false;
|
|
850
|
+
|
|
851
|
+
outputStatus(
|
|
852
|
+
{
|
|
853
|
+
type: 'status',
|
|
854
|
+
mode: 'stdin-stream',
|
|
855
|
+
message: alwaysAcceptStdin
|
|
856
|
+
? 'Agent CLI in continuous listening mode. Accepts JSON and plain text input.'
|
|
857
|
+
: 'Agent CLI in single-message mode. Accepts JSON and plain text input.',
|
|
858
|
+
hint: 'Press CTRL+C to exit. Use --help for options.',
|
|
859
|
+
acceptedFormats: isInteractive
|
|
860
|
+
? ['JSON object with "message" field', 'Plain text']
|
|
861
|
+
: ['JSON object with "message" field'],
|
|
862
|
+
options: {
|
|
863
|
+
interactive: isInteractive,
|
|
864
|
+
autoMergeQueuedMessages: autoMerge,
|
|
865
|
+
alwaysAcceptStdin,
|
|
866
|
+
compactJson,
|
|
867
|
+
},
|
|
868
|
+
},
|
|
869
|
+
compactJson
|
|
870
|
+
);
|
|
871
|
+
|
|
872
|
+
// Use continuous mode if --always-accept-stdin is enabled (default)
|
|
873
|
+
if (alwaysAcceptStdin) {
|
|
874
|
+
await runContinuousAgentMode(argv);
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
// Single-message mode (--no-always-accept-stdin)
|
|
879
|
+
const timeout = argv['stdin-stream-timeout'] ?? null;
|
|
880
|
+
const input = await readStdinWithTimeout(timeout);
|
|
881
|
+
const trimmedInput = input.trim();
|
|
882
|
+
|
|
883
|
+
if (trimmedInput === '') {
|
|
884
|
+
outputStatus(
|
|
885
|
+
{
|
|
886
|
+
type: 'status',
|
|
887
|
+
message: 'No input received. Exiting.',
|
|
888
|
+
},
|
|
889
|
+
compactJson
|
|
890
|
+
);
|
|
891
|
+
yargsInstance.showHelp();
|
|
892
|
+
process.exit(0);
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
// Try to parse as JSON, if it fails treat it as plain text message
|
|
896
|
+
let request;
|
|
897
|
+
try {
|
|
898
|
+
request = JSON.parse(trimmedInput);
|
|
899
|
+
} catch (_e) {
|
|
900
|
+
// Not JSON
|
|
901
|
+
if (!isInteractive) {
|
|
902
|
+
// In non-interactive mode, only accept JSON
|
|
903
|
+
outputStatus(
|
|
904
|
+
{
|
|
905
|
+
type: 'error',
|
|
906
|
+
message:
|
|
907
|
+
'Invalid JSON input. In non-interactive mode (--no-interactive), only JSON input is accepted.',
|
|
908
|
+
hint: 'Use --interactive to accept plain text, or provide valid JSON: {"message": "your text"}',
|
|
909
|
+
},
|
|
910
|
+
compactJson
|
|
911
|
+
);
|
|
912
|
+
process.exit(1);
|
|
913
|
+
}
|
|
914
|
+
// In interactive mode, treat as plain text message
|
|
915
|
+
request = {
|
|
916
|
+
message: trimmedInput,
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
// Run agent mode
|
|
921
|
+
await runAgentMode(argv, request);
|
|
922
|
+
},
|
|
767
923
|
})
|
|
768
924
|
// Initialize logging early for all CLI commands
|
|
769
925
|
// This prevents debug output from appearing in CLI unless --verbose is used
|
|
@@ -815,124 +971,8 @@ async function main() {
|
|
|
815
971
|
})
|
|
816
972
|
.help();
|
|
817
973
|
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
// If a command was executed (like mcp), yargs handles it
|
|
821
|
-
// Otherwise, check if we should run in agent mode (stdin piped)
|
|
822
|
-
const commandExecuted = argv._ && argv._.length > 0;
|
|
823
|
-
|
|
824
|
-
if (!commandExecuted) {
|
|
825
|
-
const compactJson = argv['compact-json'] === true;
|
|
826
|
-
|
|
827
|
-
// Check if --prompt flag was provided
|
|
828
|
-
if (argv.prompt) {
|
|
829
|
-
// Direct prompt mode - bypass stdin entirely
|
|
830
|
-
const request = { message: argv.prompt };
|
|
831
|
-
await runAgentMode(argv, request);
|
|
832
|
-
return;
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
// Check if --disable-stdin was set without --prompt
|
|
836
|
-
if (argv['disable-stdin']) {
|
|
837
|
-
// Output a helpful message suggesting to use --prompt
|
|
838
|
-
outputStatus(
|
|
839
|
-
{
|
|
840
|
-
type: 'error',
|
|
841
|
-
message:
|
|
842
|
-
'No prompt provided. Use -p/--prompt to specify a message, or remove --disable-stdin to read from stdin.',
|
|
843
|
-
hint: 'Example: agent -p "Hello, how are you?"',
|
|
844
|
-
},
|
|
845
|
-
compactJson
|
|
846
|
-
);
|
|
847
|
-
process.exit(1);
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
// Check if stdin is a TTY (interactive terminal)
|
|
851
|
-
// If it is, show help instead of waiting for input
|
|
852
|
-
if (process.stdin.isTTY) {
|
|
853
|
-
yargsInstance.showHelp();
|
|
854
|
-
process.exit(0);
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
// stdin is piped - enter stdin listening mode
|
|
858
|
-
// Output status message to inform user what's happening
|
|
859
|
-
const isInteractive = argv.interactive !== false;
|
|
860
|
-
const autoMerge = argv['auto-merge-queued-messages'] !== false;
|
|
861
|
-
const alwaysAcceptStdin = argv['always-accept-stdin'] !== false;
|
|
862
|
-
|
|
863
|
-
outputStatus(
|
|
864
|
-
{
|
|
865
|
-
type: 'status',
|
|
866
|
-
mode: 'stdin-stream',
|
|
867
|
-
message: alwaysAcceptStdin
|
|
868
|
-
? 'Agent CLI in continuous listening mode. Accepts JSON and plain text input.'
|
|
869
|
-
: 'Agent CLI in single-message mode. Accepts JSON and plain text input.',
|
|
870
|
-
hint: 'Press CTRL+C to exit. Use --help for options.',
|
|
871
|
-
acceptedFormats: isInteractive
|
|
872
|
-
? ['JSON object with "message" field', 'Plain text']
|
|
873
|
-
: ['JSON object with "message" field'],
|
|
874
|
-
options: {
|
|
875
|
-
interactive: isInteractive,
|
|
876
|
-
autoMergeQueuedMessages: autoMerge,
|
|
877
|
-
alwaysAcceptStdin,
|
|
878
|
-
compactJson,
|
|
879
|
-
},
|
|
880
|
-
},
|
|
881
|
-
compactJson
|
|
882
|
-
);
|
|
883
|
-
|
|
884
|
-
// Use continuous mode if --always-accept-stdin is enabled (default)
|
|
885
|
-
if (alwaysAcceptStdin) {
|
|
886
|
-
await runContinuousAgentMode(argv);
|
|
887
|
-
return;
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
// Single-message mode (--no-always-accept-stdin)
|
|
891
|
-
// Read stdin with optional timeout
|
|
892
|
-
const timeout = argv['stdin-stream-timeout'] ?? null;
|
|
893
|
-
const input = await readStdinWithTimeout(timeout);
|
|
894
|
-
const trimmedInput = input.trim();
|
|
895
|
-
|
|
896
|
-
if (trimmedInput === '') {
|
|
897
|
-
outputStatus(
|
|
898
|
-
{
|
|
899
|
-
type: 'status',
|
|
900
|
-
message: 'No input received. Exiting.',
|
|
901
|
-
},
|
|
902
|
-
compactJson
|
|
903
|
-
);
|
|
904
|
-
yargsInstance.showHelp();
|
|
905
|
-
process.exit(0);
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
// Try to parse as JSON, if it fails treat it as plain text message
|
|
909
|
-
let request;
|
|
910
|
-
try {
|
|
911
|
-
request = JSON.parse(trimmedInput);
|
|
912
|
-
} catch (_e) {
|
|
913
|
-
// Not JSON
|
|
914
|
-
if (!isInteractive) {
|
|
915
|
-
// In non-interactive mode, only accept JSON
|
|
916
|
-
outputStatus(
|
|
917
|
-
{
|
|
918
|
-
type: 'error',
|
|
919
|
-
message:
|
|
920
|
-
'Invalid JSON input. In non-interactive mode (--no-interactive), only JSON input is accepted.',
|
|
921
|
-
hint: 'Use --interactive to accept plain text, or provide valid JSON: {"message": "your text"}',
|
|
922
|
-
},
|
|
923
|
-
compactJson
|
|
924
|
-
);
|
|
925
|
-
process.exit(1);
|
|
926
|
-
}
|
|
927
|
-
// In interactive mode, treat as plain text message
|
|
928
|
-
request = {
|
|
929
|
-
message: trimmedInput,
|
|
930
|
-
};
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
// Run agent mode
|
|
934
|
-
await runAgentMode(argv, request);
|
|
935
|
-
}
|
|
974
|
+
// Parse arguments (handlers will be called automatically)
|
|
975
|
+
await yargsInstance.argv;
|
|
936
976
|
} catch (error) {
|
|
937
977
|
hasError = true;
|
|
938
978
|
console.error(
|