@tyvm/knowhow 0.0.110 → 0.0.112

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.
Files changed (54) hide show
  1. package/package.json +1 -1
  2. package/scripts/test-repetition-hint.ts +234 -0
  3. package/src/auth/browserLogin.ts +129 -3
  4. package/src/chat/CliChatService.ts +14 -6
  5. package/src/chat/modules/AgentModule.ts +4 -1
  6. package/src/chat/modules/ClipboardImageModule.ts +136 -0
  7. package/src/chat/modules/InternalChatModule.ts +3 -0
  8. package/src/chat/modules/RendererModule.ts +30 -2
  9. package/src/clients/xai.ts +20 -3
  10. package/src/login.ts +3 -2
  11. package/src/processors/CustomVariables.ts +175 -0
  12. package/src/services/EventService.ts +5 -33
  13. package/src/services/Mcp.ts +14 -1
  14. package/src/utils/http.ts +9 -2
  15. package/src/utils/index.ts +1 -0
  16. package/tests/fixtures/fake-secret.txt +1 -0
  17. package/tests/manual/modalities/xai.modalities.test.ts +1 -1
  18. package/tests/processors/CustomVariables.test.ts +416 -1
  19. package/ts_build/package.json +1 -1
  20. package/ts_build/src/auth/browserLogin.d.ts +2 -0
  21. package/ts_build/src/auth/browserLogin.js +91 -3
  22. package/ts_build/src/auth/browserLogin.js.map +1 -1
  23. package/ts_build/src/chat/CliChatService.js +9 -4
  24. package/ts_build/src/chat/CliChatService.js.map +1 -1
  25. package/ts_build/src/chat/modules/AgentModule.js +3 -1
  26. package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
  27. package/ts_build/src/chat/modules/ClipboardImageModule.d.ts +15 -0
  28. package/ts_build/src/chat/modules/ClipboardImageModule.js +157 -0
  29. package/ts_build/src/chat/modules/ClipboardImageModule.js.map +1 -0
  30. package/ts_build/src/chat/modules/InternalChatModule.d.ts +1 -0
  31. package/ts_build/src/chat/modules/InternalChatModule.js +3 -0
  32. package/ts_build/src/chat/modules/InternalChatModule.js.map +1 -1
  33. package/ts_build/src/chat/modules/RendererModule.js +30 -1
  34. package/ts_build/src/chat/modules/RendererModule.js.map +1 -1
  35. package/ts_build/src/clients/xai.js +14 -2
  36. package/ts_build/src/clients/xai.js.map +1 -1
  37. package/ts_build/src/login.js +2 -2
  38. package/ts_build/src/login.js.map +1 -1
  39. package/ts_build/src/processors/CustomVariables.d.ts +10 -0
  40. package/ts_build/src/processors/CustomVariables.js +127 -0
  41. package/ts_build/src/processors/CustomVariables.js.map +1 -1
  42. package/ts_build/src/services/EventService.d.ts +0 -4
  43. package/ts_build/src/services/EventService.js +4 -15
  44. package/ts_build/src/services/EventService.js.map +1 -1
  45. package/ts_build/src/services/Mcp.js +9 -1
  46. package/ts_build/src/services/Mcp.js.map +1 -1
  47. package/ts_build/src/utils/http.d.ts +2 -1
  48. package/ts_build/src/utils/http.js +11 -2
  49. package/ts_build/src/utils/http.js.map +1 -1
  50. package/ts_build/src/utils/index.js.map +1 -1
  51. package/ts_build/tests/manual/modalities/xai.modalities.test.js +1 -1
  52. package/ts_build/tests/manual/modalities/xai.modalities.test.js.map +1 -1
  53. package/ts_build/tests/processors/CustomVariables.test.js +347 -0
  54. package/ts_build/tests/processors/CustomVariables.test.js.map +1 -1
@@ -1,6 +1,7 @@
1
- import { Message } from "../../src/clients/types";
1
+ import { Message } from "../../src/clients/types";
2
2
  import { CustomVariables } from "../../src/processors/CustomVariables";
3
3
  import { ToolsService } from "../../src/services";
4
+ import * as fs from "fs";
4
5
 
5
6
  describe("CustomVariables", () => {
6
7
  let customVariables: CustomVariables;
@@ -553,4 +554,418 @@ describe("CustomVariables", () => {
553
554
  expect(modifiedMessages[0].content).toBe("Empty: '' Spaces: ' '");
554
555
  });
555
556
  });
557
+
558
+ describe("JWT token use case", () => {
559
+ let setVariableFunction: (name: string, contents: any) => string;
560
+
561
+ const LONG_JWT =
562
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9." +
563
+ "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3MTYyMzkwMjIsInJvbGVzIjpbImFkbWluIiwidXNlciJdLCJvcmciOiJhY21lLWNvcnAiLCJlbWFpbCI6ImpvaG5AYWNtZS5jb20ifQ." +
564
+ "SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
565
+
566
+ beforeEach(() => {
567
+ const addFunctionsCalls = mockToolsService.addFunctions.mock.calls;
568
+ const setVariableCall = addFunctionsCalls.find(
569
+ (call) => call[0].setVariable
570
+ );
571
+ setVariableFunction = setVariableCall[0].setVariable;
572
+ });
573
+
574
+ it("should store a long JWT and substitute it in a tool call argument", async () => {
575
+ // LLM stores the JWT once
576
+ setVariableFunction("jwt_token", LONG_JWT);
577
+
578
+ // LLM uses {{jwt_token}} in a tool call instead of repeating the full JWT
579
+ const messages: Message[] = [
580
+ {
581
+ role: "assistant",
582
+ content: null,
583
+ tool_calls: [
584
+ {
585
+ id: "call_abc",
586
+ type: "function",
587
+ function: {
588
+ name: "execCommand",
589
+ arguments: JSON.stringify({
590
+ command: 'curl -H "Authorization: Bearer {{jwt_token}}" https://api.example.com/data',
591
+ }),
592
+ },
593
+ },
594
+ ],
595
+ },
596
+ ];
597
+
598
+ const processor = customVariables.createProcessor();
599
+ const modifiedMessages = [...messages];
600
+ await processor(messages, modifiedMessages);
601
+
602
+ // The tool call argument should have the full JWT substituted in
603
+ const args = JSON.parse(modifiedMessages[0].tool_calls![0].function.arguments);
604
+ expect(args.command).toBe(
605
+ `curl -H "Authorization: Bearer ${LONG_JWT}" https://api.example.com/data`
606
+ );
607
+ // And the original message should be unchanged
608
+ expect(messages[0].tool_calls![0].function.arguments).toContain("{{jwt_token}}");
609
+ });
610
+
611
+ it("should allow reusing the JWT variable across multiple tool calls without repeating it", async () => {
612
+ setVariableFunction("jwt_token", LONG_JWT);
613
+
614
+ // Simulate multiple tool calls all using {{jwt_token}} - LLM never outputs full JWT again
615
+ const toolCallMessages: Message[] = [
616
+ {
617
+ role: "assistant",
618
+ content: null,
619
+ tool_calls: [
620
+ {
621
+ id: "call_1",
622
+ type: "function",
623
+ function: {
624
+ name: "execCommand",
625
+ arguments: JSON.stringify({ command: 'curl -H "Authorization: Bearer {{jwt_token}}" https://api.example.com/users' }),
626
+ },
627
+ },
628
+ ],
629
+ },
630
+ {
631
+ role: "assistant",
632
+ content: null,
633
+ tool_calls: [
634
+ {
635
+ id: "call_2",
636
+ type: "function",
637
+ function: {
638
+ name: "execCommand",
639
+ arguments: JSON.stringify({ command: 'curl -H "Authorization: Bearer {{jwt_token}}" https://api.example.com/posts' }),
640
+ },
641
+ },
642
+ ],
643
+ },
644
+ ];
645
+
646
+ const processor = customVariables.createProcessor();
647
+ const modifiedMessages = [...toolCallMessages];
648
+ await processor(toolCallMessages, modifiedMessages);
649
+
650
+ // Both tool calls should have the full JWT
651
+ const args1 = JSON.parse(modifiedMessages[0].tool_calls![0].function.arguments);
652
+ const args2 = JSON.parse(modifiedMessages[1].tool_calls![0].function.arguments);
653
+
654
+ expect(args1.command).toContain(LONG_JWT);
655
+ expect(args2.command).toContain(LONG_JWT);
656
+
657
+ // Original messages should still have the placeholder
658
+ expect(toolCallMessages[0].tool_calls![0].function.arguments).toContain("{{jwt_token}}");
659
+ expect(toolCallMessages[1].tool_calls![0].function.arguments).toContain("{{jwt_token}}");
660
+ });
661
+
662
+ describe("storeToolCallToVariable privacy proof", () => {
663
+ /**
664
+ * This test proves that when an LLM uses storeToolCallToVariable to load
665
+ * a sensitive value (e.g. a JWT from a file), the LLM *never* sees the
666
+ * actual value in any message. The tool response only says
667
+ * "stored in variable X" - the raw secret stays server-side in the
668
+ * variable storage, and the LLM uses {{jwt_token}} as a placeholder.
669
+ */
670
+ let storeToolCallFunction: (
671
+ varName: string,
672
+ toolName: string,
673
+ toolArgs: string
674
+ ) => Promise<string>;
675
+ let setVariableFunction: (name: string, contents: any) => string;
676
+
677
+ beforeEach(() => {
678
+ const addFunctionsCalls = mockToolsService.addFunctions.mock.calls;
679
+ storeToolCallFunction = addFunctionsCalls.find(
680
+ (call) => call[0].storeToolCallToVariable
681
+ )![0].storeToolCallToVariable;
682
+ setVariableFunction = addFunctionsCalls.find(
683
+ (call) => call[0].setVariable
684
+ )![0].setVariable;
685
+ });
686
+
687
+ it("should store JWT from a file without the LLM ever seeing the value", async () => {
688
+ // Simulate a tool that reads the JWT file (like execCommand cat .knowhow/.jwt)
689
+ const jwtContent = fs.readFileSync(`${__dirname}/../fixtures/fake-secret.txt`, "utf-8").trim();
690
+
691
+ // The tool returns the file contents - but only to storeToolCallToVariable, not to the LLM
692
+ mockToolsService.callTool.mockResolvedValue(jwtContent as any);
693
+
694
+ // LLM calls: storeToolCallToVariable("jwt_token", "execCommand", '{"command":"cat .knowhow/.jwt"}')
695
+ const toolResponse = await storeToolCallFunction(
696
+ "jwt_token",
697
+ "execCommand",
698
+ JSON.stringify({ command: "cat tests/fixtures/fake-secret.txt" })
699
+ );
700
+
701
+ // The LLM only sees this confirmation message - NOT the JWT value itself
702
+ expect(toolResponse).toBe(
703
+ 'Tool call result for "execCommand" has been stored in variable "jwt_token".'
704
+ );
705
+ expect(toolResponse).not.toContain(jwtContent);
706
+ expect(toolResponse).not.toContain("eyJ"); // No JWT content in the response
707
+
708
+ // The JWT IS stored internally and can be substituted into future tool calls
709
+ const processor = customVariables.createProcessor();
710
+
711
+ const messages: Message[] = [
712
+ {
713
+ role: "assistant",
714
+ content: null,
715
+ tool_calls: [
716
+ {
717
+ id: "call_curl",
718
+ type: "function",
719
+ function: {
720
+ name: "execCommand",
721
+ // LLM uses placeholder - never outputs the actual JWT
722
+ arguments: JSON.stringify({
723
+ command: 'curl -H "Authorization: Bearer {{jwt_token}}" https://api.example.com',
724
+ }),
725
+ },
726
+ },
727
+ ],
728
+ },
729
+ ];
730
+
731
+ const modifiedMessages = [...messages];
732
+ await processor(messages, modifiedMessages);
733
+
734
+ // The actual JWT is injected at execution time
735
+ const args = JSON.parse(modifiedMessages[0].tool_calls![0].function.arguments);
736
+ expect(args.command).toContain(jwtContent);
737
+
738
+ // But the original message still has the placeholder (LLM never saw the JWT)
739
+ expect(messages[0].tool_calls![0].function.arguments).toContain("{{jwt_token}}");
740
+ expect(messages[0].tool_calls![0].function.arguments).not.toContain(jwtContent);
741
+ });
742
+
743
+ it("should prove the full storeToolCallToVariable flow with real JWT file", async () => {
744
+ // Use a fake secret file instead of a real JWT, to prove the secret is never exposed
745
+ const fakePath = `${__dirname}/../fixtures/fake-secret.txt`;
746
+ const fakeSecret = fs.readFileSync(fakePath, "utf-8").trim();
747
+
748
+ // Simulate the execCommand tool returning the JWT file contents
749
+ mockToolsService.callTool.mockResolvedValue(fakeSecret as any);
750
+
751
+ // Step 1: LLM stores JWT via storeToolCallToVariable - only gets a confirmation back
752
+ const storeResponse = await storeToolCallFunction(
753
+ "jwt_token",
754
+ "execCommand",
755
+ JSON.stringify({ command: `cat ${fakePath}` })
756
+ );
757
+
758
+ // LLM message history only contains this - not the JWT
759
+ expect(storeResponse).toContain('stored in variable "jwt_token"');
760
+ expect(storeResponse).not.toContain(fakeSecret);
761
+
762
+ // Step 2: LLM uses {{jwt_token}} in subsequent curl calls
763
+ const processor = customVariables.createProcessor();
764
+ const curlMessages: Message[] = [
765
+ {
766
+ role: "assistant",
767
+ content: null,
768
+ tool_calls: [
769
+ {
770
+ id: "call_api1",
771
+ type: "function",
772
+ function: {
773
+ name: "execCommand",
774
+ arguments: JSON.stringify({
775
+ command: 'curl -H "Authorization: Bearer {{jwt_token}}" https://api.example.com/users',
776
+ }),
777
+ },
778
+ },
779
+ ],
780
+ },
781
+ {
782
+ role: "assistant",
783
+ content: null,
784
+ tool_calls: [
785
+ {
786
+ id: "call_api2",
787
+ type: "function",
788
+ function: {
789
+ name: "execCommand",
790
+ arguments: JSON.stringify({
791
+ command: 'curl -H "Authorization: Bearer {{jwt_token}}" https://api.example.com/posts',
792
+ }),
793
+ },
794
+ },
795
+ ],
796
+ },
797
+ ];
798
+
799
+ const modifiedMessages = [...curlMessages];
800
+ await processor(curlMessages, modifiedMessages);
801
+
802
+ // Both calls get the real JWT injected
803
+ const args1 = JSON.parse(modifiedMessages[0].tool_calls![0].function.arguments);
804
+ const args2 = JSON.parse(modifiedMessages[1].tool_calls![0].function.arguments);
805
+ expect(args1.command).toContain(fakeSecret);
806
+ expect(args2.command).toContain(fakeSecret);
807
+ // Original messages still have placeholder - JWT never appeared in LLM messages
808
+ expect(curlMessages[0].tool_calls![0].function.arguments).not.toContain(fakeSecret);
809
+ expect(curlMessages[1].tool_calls![0].function.arguments).not.toContain(fakeSecret);
810
+ });
811
+ });
812
+
813
+ describe("createRepetitionHintProcessor", () => {
814
+ it("should append a hint when a large string is repeated across multiple tool calls", async () => {
815
+ const longString = "x".repeat(100);
816
+ const messages: Message[] = [
817
+ {
818
+ role: "assistant",
819
+ content: null,
820
+ tool_calls: [{ id: "c1", type: "function", function: { name: "toolA", arguments: JSON.stringify({ token: longString }) } }],
821
+ },
822
+ {
823
+ role: "assistant",
824
+ content: null,
825
+ tool_calls: [{ id: "c2", type: "function", function: { name: "toolA", arguments: JSON.stringify({ token: longString }) } }],
826
+ },
827
+ ];
828
+
829
+ const processor = customVariables.createRepetitionHintProcessor({ minLength: 50, minRepetitions: 2 });
830
+ const modified = JSON.parse(JSON.stringify(messages));
831
+ await processor(messages, modified);
832
+
833
+ // A hint message should be appended
834
+ const hint = modified[modified.length - 1];
835
+ expect(hint.role).toBe("user");
836
+ expect(hint.content).toContain("large repetitions");
837
+ expect(hint.content).toContain("toolA");
838
+ expect(hint.content).toContain("setVariable");
839
+ expect(hint.content).toContain("storeToolCallToVariable");
840
+ });
841
+
842
+ it("should not append a hint when strings are short", async () => {
843
+ const messages: Message[] = [
844
+ {
845
+ role: "assistant",
846
+ content: null,
847
+ tool_calls: [{ id: "c1", type: "function", function: { name: "toolA", arguments: JSON.stringify({ token: "short" }) } }],
848
+ },
849
+ {
850
+ role: "assistant",
851
+ content: null,
852
+ tool_calls: [{ id: "c2", type: "function", function: { name: "toolA", arguments: JSON.stringify({ token: "short" }) } }],
853
+ },
854
+ ];
855
+
856
+ const processor = customVariables.createRepetitionHintProcessor({ minLength: 50, minRepetitions: 2 });
857
+ const modified = JSON.parse(JSON.stringify(messages));
858
+ await processor(messages, modified);
859
+
860
+ // No hint should be appended - length of messages unchanged
861
+ expect(modified.length).toBe(messages.length);
862
+ });
863
+
864
+ it("should not append a hint when a large string appears only once", async () => {
865
+ const longString = "y".repeat(100);
866
+ const messages: Message[] = [
867
+ {
868
+ role: "assistant",
869
+ content: null,
870
+ tool_calls: [{ id: "c1", type: "function", function: { name: "toolB", arguments: JSON.stringify({ value: longString }) } }],
871
+ },
872
+ {
873
+ role: "assistant",
874
+ content: null,
875
+ tool_calls: [{ id: "c2", type: "function", function: { name: "toolB", arguments: JSON.stringify({ value: "something_different_entirely" }) } }],
876
+ },
877
+ ];
878
+
879
+ const processor = customVariables.createRepetitionHintProcessor({ minLength: 50, minRepetitions: 2 });
880
+ const modified = JSON.parse(JSON.stringify(messages));
881
+ await processor(messages, modified);
882
+ expect(modified.length).toBe(messages.length);
883
+ });
884
+
885
+ it("should list all tool names that use repeated values", async () => {
886
+ const longString = "z".repeat(100);
887
+ const messages: Message[] = [
888
+ {
889
+ role: "assistant",
890
+ content: null,
891
+ tool_calls: [{ id: "c1", type: "function", function: { name: "toolX", arguments: JSON.stringify({ auth: longString }) } }],
892
+ },
893
+ {
894
+ role: "assistant",
895
+ content: null,
896
+ tool_calls: [{ id: "c2", type: "function", function: { name: "toolY", arguments: JSON.stringify({ auth: longString }) } }],
897
+ },
898
+ {
899
+ role: "assistant",
900
+ content: null,
901
+ tool_calls: [{ id: "c3", type: "function", function: { name: "toolZ", arguments: JSON.stringify({ auth: longString }) } }],
902
+ },
903
+ ];
904
+ const processor = customVariables.createRepetitionHintProcessor({ minLength: 50, minRepetitions: 2 });
905
+ const modified = JSON.parse(JSON.stringify(messages));
906
+ await processor(messages, modified);
907
+ const hint = modified[modified.length - 1];
908
+ expect(hint.content).toContain("toolX");
909
+ expect(hint.content).toContain("toolY");
910
+ expect(hint.content).toContain("toolZ");
911
+ });
912
+
913
+ it("should use default options when none provided", async () => {
914
+ const longString = "a".repeat(60); // > 50 default minLength
915
+ const messages: Message[] = [
916
+ {
917
+ role: "assistant",
918
+ content: null,
919
+ tool_calls: [{ id: "c1", type: "function", function: { name: "myTool", arguments: JSON.stringify({ key: longString }) } }],
920
+ },
921
+ {
922
+ role: "assistant",
923
+ content: null,
924
+ tool_calls: [{ id: "c2", type: "function", function: { name: "myTool", arguments: JSON.stringify({ key: longString }) } }],
925
+ },
926
+ ];
927
+ const processor = customVariables.createRepetitionHintProcessor(); // default options
928
+ const modified = JSON.parse(JSON.stringify(messages));
929
+ await processor(messages, modified);
930
+ const hint = modified[modified.length - 1];
931
+ expect(hint.role).toBe("user");
932
+ expect(hint.content).toContain("myTool");
933
+ });
934
+
935
+ it("should detect repeated substrings embedded within different larger strings", async () => {
936
+ // Simulate the JWT-in-curl-command pattern:
937
+ // Each command is unique but all contain the same JWT substring
938
+ const jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJmYWtlLXVzZXItaWQifQ.FAKE_SIGNATURE_DO_NOT_USE";
939
+ const messages: Message[] = [
940
+ {
941
+ role: "assistant",
942
+ content: null,
943
+ tool_calls: [{
944
+ id: "c1", type: "function",
945
+ function: { name: "execCommand", arguments: JSON.stringify({ command: `curl -H 'Authorization: Bearer ${jwt}' https://api.example.com/endpoint-one` }) }
946
+ }],
947
+ },
948
+ {
949
+ role: "assistant",
950
+ content: null,
951
+ tool_calls: [{
952
+ id: "c2", type: "function",
953
+ function: { name: "execCommand", arguments: JSON.stringify({ command: `curl -H 'Authorization: Bearer ${jwt}' https://api.example.com/endpoint-two --data '{"key":"value"}'` }) }
954
+ }],
955
+ },
956
+ ];
957
+
958
+ const processor = customVariables.createRepetitionHintProcessor({ minLength: 50, minRepetitions: 2, minSubstringLength: 50 });
959
+ const modified = JSON.parse(JSON.stringify(messages));
960
+ await processor(messages, modified);
961
+
962
+ // Should have detected the JWT appearing in both commands and added a hint
963
+ expect(modified.length).toBe(3);
964
+ const hint = modified[modified.length - 1];
965
+ expect(hint.role).toBe("user");
966
+ expect(hint.content).toContain("execCommand");
967
+ expect(hint.content).toContain("setVariable");
968
+ });
969
+ });
970
+ });
556
971
  });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tyvm/knowhow",
3
- "version": "0.0.110",
3
+ "version": "0.0.112",
4
4
  "description": "ai cli with plugins and agents",
5
5
  "main": "ts_build/src/index.js",
6
6
  "bin": {
@@ -6,7 +6,9 @@ export declare class BrowserLoginService {
6
6
  private createSession;
7
7
  private storeJwt;
8
8
  private sleep;
9
+ private waitForDeviceConfirmation;
9
10
  private setupSignalHandlers;
10
11
  }
12
+ export declare function getCliUserAgent(): string;
11
13
  export declare function openBrowser(url: string): Promise<void>;
12
14
  export declare function validateJwt(jwt: string): boolean;
@@ -37,6 +37,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.BrowserLoginService = void 0;
40
+ exports.getCliUserAgent = getCliUserAgent;
40
41
  exports.openBrowser = openBrowser;
41
42
  exports.validateJwt = validateJwt;
42
43
  const http_1 = __importDefault(require("../utils/http"));
@@ -44,6 +45,7 @@ const child_process_1 = require("child_process");
44
45
  const util_1 = require("util");
45
46
  const os = __importStar(require("os"));
46
47
  const fs = __importStar(require("fs"));
48
+ const path = __importStar(require("path"));
47
49
  const KnowhowClient_1 = require("../services/KnowhowClient");
48
50
  const spinner_1 = require("./spinner");
49
51
  const errors_1 = require("./errors");
@@ -94,9 +96,25 @@ class BrowserLoginService {
94
96
  spinner.stop();
95
97
  spinner.start("Authentication successful! Retrieving token");
96
98
  const tokenResponse = await http_1.default.post(`${this.baseUrl}/api/cli-login/session/${sessionData.sessionId}/token`);
97
- const jwt = tokenResponse.data.jwt;
98
- await this.storeJwt(jwt);
99
+ const tokenData = tokenResponse.data;
99
100
  spinner.stop();
101
+ if (tokenData.requiresDeviceConfirmation) {
102
+ if (tokenData.jwt) {
103
+ await this.storeJwt(tokenData.jwt);
104
+ }
105
+ console.log("\n⚠️ New device detected — device confirmation required!");
106
+ console.log("─────────────────────────────────────────────────────");
107
+ console.log("A confirmation code has been sent to your email.");
108
+ console.log("You must confirm this device in your browser to complete login.");
109
+ console.log("\nPlease check the browser window you just used to approve the CLI session.");
110
+ console.log("Enter the email code there to confirm this device.");
111
+ console.log("\nAlternatively, visit your settings page:");
112
+ console.log(` ${process.env.KNOWHOW_FRONTEND_URL || "https://knowhow.tyvm.ai"}/settings?tab=security`);
113
+ console.log("─────────────────────────────────────────────────────\n");
114
+ await this.waitForDeviceConfirmation(tokenData.jwt);
115
+ return;
116
+ }
117
+ await this.storeJwt(tokenData.jwt);
100
118
  return;
101
119
  }
102
120
  else if (status.status.toLowerCase() === "denied") {
@@ -123,7 +141,7 @@ class BrowserLoginService {
123
141
  }
124
142
  async createSession() {
125
143
  try {
126
- const response = await http_1.default.post(`${this.baseUrl}/api/cli-login/session`, {});
144
+ const response = await http_1.default.post(`${this.baseUrl}/api/cli-login/session`, {}, { headers: { "User-Agent": getCliUserAgent() } });
127
145
  return response.data;
128
146
  }
129
147
  catch (error) {
@@ -145,6 +163,61 @@ class BrowserLoginService {
145
163
  async sleep(ms) {
146
164
  return new Promise((resolve) => setTimeout(resolve, ms));
147
165
  }
166
+ async waitForDeviceConfirmation(jwt) {
167
+ const spinner = new spinner_1.Spinner();
168
+ spinner.start("Waiting for device confirmation");
169
+ let isCancelled = false;
170
+ const cancelHandler = () => {
171
+ isCancelled = true;
172
+ spinner.stop();
173
+ console.log("\n\nCancelled. Your token is stored — once you confirm the device, re-run your command.");
174
+ process.exit(0);
175
+ };
176
+ process.once("SIGINT", cancelHandler);
177
+ const maxAttempts = 120;
178
+ let attempt = 0;
179
+ while (attempt < maxAttempts) {
180
+ attempt++;
181
+ for (let i = 0; i < 10; i++) {
182
+ await this.sleep(500);
183
+ if (isCancelled)
184
+ return;
185
+ }
186
+ try {
187
+ const response = await http_1.default.get(`${this.baseUrl}/api/users/me`, {
188
+ headers: { Authorization: `Bearer ${jwt}` },
189
+ timeout: 10000,
190
+ });
191
+ if (response.status === 200) {
192
+ spinner.stop();
193
+ process.removeListener("SIGINT", cancelHandler);
194
+ console.log("✅ Device confirmed! You are now logged in.");
195
+ return;
196
+ }
197
+ }
198
+ catch (error) {
199
+ if (http_1.default.isHttpError(error)) {
200
+ if (error.status === 403) {
201
+ continue;
202
+ }
203
+ if (error.status === 401) {
204
+ if (attempt >= 10) {
205
+ spinner.stop();
206
+ process.removeListener("SIGINT", cancelHandler);
207
+ throw new errors_1.BrowserLoginError("Token expired or revoked during device confirmation. Please run 'knowhow login' again.", "TOKEN_EXPIRED");
208
+ }
209
+ continue;
210
+ }
211
+ }
212
+ }
213
+ }
214
+ spinner.stop();
215
+ process.removeListener("SIGINT", cancelHandler);
216
+ console.log("\n⏰ Timed out waiting for device confirmation.");
217
+ console.log("Your token is stored — once you confirm the device at:");
218
+ console.log(` ${process.env.KNOWHOW_FRONTEND_URL || "https://knowhow.tyvm.ai"}/settings?tab=security`);
219
+ console.log("you can re-run your command and it will work.\n");
220
+ }
148
221
  setupSignalHandlers() {
149
222
  const gracefulShutdown = () => {
150
223
  console.log("\n\nAuthentication cancelled by user.");
@@ -154,6 +227,21 @@ class BrowserLoginService {
154
227
  }
155
228
  }
156
229
  exports.BrowserLoginService = BrowserLoginService;
230
+ function getCliUserAgent() {
231
+ let cliVersion = "unknown";
232
+ try {
233
+ const pkgPath = path.resolve(__dirname, "../../../package.json");
234
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
235
+ cliVersion = pkg.version ?? "unknown";
236
+ }
237
+ catch {
238
+ }
239
+ const platform = os.platform();
240
+ const osName = platform === "darwin" ? "macOS" :
241
+ platform === "win32" ? "Windows" :
242
+ platform === "linux" ? "Linux" : platform;
243
+ return `Knowhow CLI/${cliVersion} (${osName})`;
244
+ }
157
245
  async function openBrowser(url) {
158
246
  const execAsync = (0, util_1.promisify)(child_process_1.exec);
159
247
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"browserLogin.js","sourceRoot":"","sources":["../../../src/auth/browserLogin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"browserLogin.js","sourceRoot":"","sources":["../../../src/auth/browserLogin.ts"],"names":[],"mappings":"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"}
@@ -153,10 +153,15 @@ class CliChatService {
153
153
  }
154
154
  else {
155
155
  const availableCommands = this.getCommandsForActiveModes();
156
- console.log(`Unknown command "/${commandName}". Available commands: ${availableCommands
157
- .map((cmd) => `/${cmd.name}`)
158
- .join(", ")}`);
159
- return true;
156
+ const looksLikeFilepath = commandName.includes("/") ||
157
+ commandName.includes(".") ||
158
+ commandName.includes("\\");
159
+ if (!looksLikeFilepath) {
160
+ console.log(`Unknown command "/${commandName}". Available commands: ${availableCommands
161
+ .map((cmd) => `/${cmd.name}`)
162
+ .join(", ")}`);
163
+ return true;
164
+ }
160
165
  }
161
166
  }
162
167
  for (const module of this.modules) {