@staff0rd/assist 0.755.2 → 0.757.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 +9 -30
- package/claude/skills/review-ci/scripts/review.mjs +111 -111
- package/dist/commands/sessions/web/bundle.js +412 -412
- package/dist/index.js +394 -730
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { Command } from "commander";
|
|
|
6
6
|
// package.json
|
|
7
7
|
var package_default = {
|
|
8
8
|
name: "@staff0rd/assist",
|
|
9
|
-
version: "0.
|
|
9
|
+
version: "0.757.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -563,7 +563,7 @@ function stripLegacyConfigKeys(config) {
|
|
|
563
563
|
}
|
|
564
564
|
|
|
565
565
|
// src/shared/types.ts
|
|
566
|
-
import { z as
|
|
566
|
+
import { z as z4 } from "zod";
|
|
567
567
|
|
|
568
568
|
// src/shared/adviceFragmentNames.ts
|
|
569
569
|
var adviceFragmentTitles = {
|
|
@@ -638,267 +638,273 @@ function isSecretSchemaNode(node) {
|
|
|
638
638
|
return meta?.[SECRET_META_KEY] === true;
|
|
639
639
|
}
|
|
640
640
|
|
|
641
|
+
// src/shared/sessionLinkSchema.ts
|
|
642
|
+
import { z as z3 } from "zod";
|
|
643
|
+
var SSH_LINK_RETIRED = "ssh links are no longer supported; relink with `assist sessions nodes link <name> --tailscale <host> --port <port>`";
|
|
644
|
+
var sessionLinkSchema = z3.preprocess(
|
|
645
|
+
(link3, ctx) => {
|
|
646
|
+
if (link3 && typeof link3 === "object" && "ssh" in link3)
|
|
647
|
+
ctx.issues.push({
|
|
648
|
+
code: "custom",
|
|
649
|
+
message: SSH_LINK_RETIRED,
|
|
650
|
+
input: link3
|
|
651
|
+
});
|
|
652
|
+
return link3;
|
|
653
|
+
},
|
|
654
|
+
z3.strictObject({ name: z3.string(), url: z3.string() })
|
|
655
|
+
);
|
|
656
|
+
|
|
641
657
|
// src/shared/types.ts
|
|
642
|
-
var transcriptConfigSchema =
|
|
643
|
-
vttDir:
|
|
644
|
-
transcriptsDir:
|
|
645
|
-
summaryDir:
|
|
658
|
+
var transcriptConfigSchema = z4.strictObject({
|
|
659
|
+
vttDir: z4.string(),
|
|
660
|
+
transcriptsDir: z4.string(),
|
|
661
|
+
summaryDir: z4.string()
|
|
646
662
|
});
|
|
647
|
-
var miroExtractSchema =
|
|
648
|
-
board:
|
|
649
|
-
frame:
|
|
650
|
-
topLeft:
|
|
651
|
-
bottomRight:
|
|
652
|
-
items:
|
|
653
|
-
ignore:
|
|
654
|
-
out:
|
|
663
|
+
var miroExtractSchema = z4.strictObject({
|
|
664
|
+
board: z4.string().optional(),
|
|
665
|
+
frame: z4.string().optional(),
|
|
666
|
+
topLeft: z4.string(),
|
|
667
|
+
bottomRight: z4.string(),
|
|
668
|
+
items: z4.string(),
|
|
669
|
+
ignore: z4.string().optional(),
|
|
670
|
+
out: z4.string().optional()
|
|
655
671
|
});
|
|
656
672
|
var DEFAULT_BACKUP_DIR = "~/.assist/backups";
|
|
657
673
|
var DEFAULT_CLONE_DIR = "~/git";
|
|
658
674
|
var assistConfigShape = {
|
|
659
|
-
advice:
|
|
660
|
-
sections:
|
|
661
|
-
extra:
|
|
662
|
-
verify:
|
|
675
|
+
advice: z4.strictObject({
|
|
676
|
+
sections: z4.partialRecord(z4.enum(adviceFragmentNames), z4.boolean()).default({}),
|
|
677
|
+
extra: z4.string().optional(),
|
|
678
|
+
verify: z4.string().optional()
|
|
663
679
|
}).optional(),
|
|
664
|
-
backlog:
|
|
665
|
-
previewComments:
|
|
680
|
+
backlog: z4.strictObject({
|
|
681
|
+
previewComments: z4.boolean().default(false)
|
|
666
682
|
}).optional(),
|
|
667
|
-
backup:
|
|
668
|
-
dir:
|
|
683
|
+
backup: z4.strictObject({
|
|
684
|
+
dir: z4.string().default(DEFAULT_BACKUP_DIR)
|
|
669
685
|
}).default({ dir: DEFAULT_BACKUP_DIR }),
|
|
670
|
-
clone:
|
|
671
|
-
baseDir:
|
|
686
|
+
clone: z4.strictObject({
|
|
687
|
+
baseDir: z4.string().default(DEFAULT_CLONE_DIR)
|
|
672
688
|
}).default({ baseDir: DEFAULT_CLONE_DIR }),
|
|
673
|
-
commit:
|
|
674
|
-
conventional:
|
|
675
|
-
pull:
|
|
676
|
-
push:
|
|
677
|
-
expectedBranch:
|
|
689
|
+
commit: z4.strictObject({
|
|
690
|
+
conventional: z4.boolean().default(false),
|
|
691
|
+
pull: z4.boolean().default(false),
|
|
692
|
+
push: z4.boolean().default(false),
|
|
693
|
+
expectedBranch: z4.string().optional()
|
|
678
694
|
}).default({ conventional: false, pull: false, push: false }),
|
|
679
|
-
branch:
|
|
680
|
-
prefix:
|
|
681
|
-
defaultBranch:
|
|
695
|
+
branch: z4.strictObject({
|
|
696
|
+
prefix: z4.string().optional(),
|
|
697
|
+
defaultBranch: z4.string().optional()
|
|
682
698
|
}).optional(),
|
|
683
|
-
devlog:
|
|
684
|
-
name:
|
|
685
|
-
ignore:
|
|
686
|
-
skip:
|
|
699
|
+
devlog: z4.strictObject({
|
|
700
|
+
name: z4.string().optional(),
|
|
701
|
+
ignore: z4.array(z4.string()).optional(),
|
|
702
|
+
skip: z4.record(z4.string(), z4.array(z4.string())).optional()
|
|
687
703
|
}).optional(),
|
|
688
|
-
notify:
|
|
689
|
-
enabled:
|
|
704
|
+
notify: z4.strictObject({
|
|
705
|
+
enabled: z4.boolean().default(true)
|
|
690
706
|
}).default({ enabled: true }),
|
|
691
|
-
complexity:
|
|
692
|
-
ignore:
|
|
707
|
+
complexity: z4.strictObject({
|
|
708
|
+
ignore: z4.array(z4.string()).default(["**/*test.ts*"])
|
|
693
709
|
}).default({ ignore: ["**/*test.ts*"] }),
|
|
694
|
-
hardcodedColors:
|
|
695
|
-
ignore:
|
|
710
|
+
hardcodedColors: z4.strictObject({
|
|
711
|
+
ignore: z4.array(z4.string()).default([])
|
|
696
712
|
}).optional(),
|
|
697
|
-
blockCodeComments:
|
|
698
|
-
ignore:
|
|
713
|
+
blockCodeComments: z4.strictObject({
|
|
714
|
+
ignore: z4.array(z4.string()).default([])
|
|
699
715
|
}).optional(),
|
|
700
|
-
restructure:
|
|
701
|
-
ignore:
|
|
702
|
-
pin:
|
|
703
|
-
maxDepth:
|
|
716
|
+
restructure: z4.strictObject({
|
|
717
|
+
ignore: z4.array(z4.string()).default([]),
|
|
718
|
+
pin: z4.array(z4.string()).default([]),
|
|
719
|
+
maxDepth: z4.number().int().positive().default(10)
|
|
704
720
|
}).optional(),
|
|
705
|
-
jira:
|
|
706
|
-
acField:
|
|
721
|
+
jira: z4.strictObject({
|
|
722
|
+
acField: z4.string().default("customfield_11937")
|
|
707
723
|
}).optional(),
|
|
708
|
-
roam:
|
|
709
|
-
clientId: secretConfigValue(
|
|
710
|
-
clientSecret: secretConfigValue(
|
|
711
|
-
accessToken: secretConfigValue(
|
|
712
|
-
refreshToken: secretConfigValue(
|
|
713
|
-
tokenExpiresAt:
|
|
724
|
+
roam: z4.strictObject({
|
|
725
|
+
clientId: secretConfigValue(z4.string()),
|
|
726
|
+
clientSecret: secretConfigValue(z4.string()),
|
|
727
|
+
accessToken: secretConfigValue(z4.string()).optional(),
|
|
728
|
+
refreshToken: secretConfigValue(z4.string()).optional(),
|
|
729
|
+
tokenExpiresAt: z4.number().optional()
|
|
714
730
|
}).optional(),
|
|
715
|
-
slack:
|
|
716
|
-
channel:
|
|
731
|
+
slack: z4.strictObject({
|
|
732
|
+
channel: z4.string().optional()
|
|
717
733
|
}).optional(),
|
|
718
|
-
prs:
|
|
719
|
-
slack:
|
|
720
|
-
required:
|
|
721
|
-
promptJira:
|
|
722
|
-
promptGithub:
|
|
723
|
-
draft:
|
|
724
|
-
readingWordsPerMinute:
|
|
734
|
+
prs: z4.strictObject({
|
|
735
|
+
slack: z4.string().optional(),
|
|
736
|
+
required: z4.boolean().default(true),
|
|
737
|
+
promptJira: z4.boolean().default(false),
|
|
738
|
+
promptGithub: z4.boolean().default(false),
|
|
739
|
+
draft: z4.boolean().default(false),
|
|
740
|
+
readingWordsPerMinute: z4.number().int().positive().optional()
|
|
725
741
|
}).optional(),
|
|
726
|
-
review:
|
|
727
|
-
codexModel:
|
|
728
|
-
highLevel:
|
|
729
|
-
criticalPaths:
|
|
730
|
-
uiPaths:
|
|
731
|
-
descriptionWordCap:
|
|
742
|
+
review: z4.strictObject({
|
|
743
|
+
codexModel: z4.string().optional(),
|
|
744
|
+
highLevel: z4.strictObject({
|
|
745
|
+
criticalPaths: z4.array(z4.string()).default([]),
|
|
746
|
+
uiPaths: z4.array(z4.string()).default([]),
|
|
747
|
+
descriptionWordCap: z4.number().int().positive().default(300)
|
|
732
748
|
}).optional()
|
|
733
749
|
}).optional(),
|
|
734
|
-
readTime:
|
|
735
|
-
wordsPerMinute:
|
|
750
|
+
readTime: z4.strictObject({
|
|
751
|
+
wordsPerMinute: z4.number().int().positive().default(200)
|
|
736
752
|
}).optional(),
|
|
737
|
-
releases:
|
|
738
|
-
streams:
|
|
739
|
-
|
|
740
|
-
name:
|
|
741
|
-
repo:
|
|
742
|
-
workflow:
|
|
743
|
-
nodes:
|
|
744
|
-
|
|
745
|
-
id:
|
|
746
|
-
environment:
|
|
747
|
-
kind:
|
|
748
|
-
label:
|
|
753
|
+
releases: z4.strictObject({
|
|
754
|
+
streams: z4.array(
|
|
755
|
+
z4.strictObject({
|
|
756
|
+
name: z4.string(),
|
|
757
|
+
repo: z4.string(),
|
|
758
|
+
workflow: z4.string(),
|
|
759
|
+
nodes: z4.array(
|
|
760
|
+
z4.strictObject({
|
|
761
|
+
id: z4.string(),
|
|
762
|
+
environment: z4.string().optional(),
|
|
763
|
+
kind: z4.enum(["build", "gate"]).optional(),
|
|
764
|
+
label: z4.string().optional()
|
|
749
765
|
})
|
|
750
766
|
),
|
|
751
|
-
edges:
|
|
767
|
+
edges: z4.array(z4.tuple([z4.string(), z4.string()])).default([])
|
|
752
768
|
})
|
|
753
769
|
).default([])
|
|
754
770
|
}).optional(),
|
|
755
|
-
worktree:
|
|
756
|
-
enabled:
|
|
757
|
-
watcher:
|
|
758
|
-
trunk:
|
|
759
|
-
includeDrafts:
|
|
760
|
-
root:
|
|
761
|
-
install:
|
|
762
|
-
commitBeforeManualChecks:
|
|
763
|
-
commitBeforePhaseEnd:
|
|
764
|
-
copy:
|
|
771
|
+
worktree: z4.strictObject({
|
|
772
|
+
enabled: z4.boolean().default(false),
|
|
773
|
+
watcher: z4.boolean().default(false),
|
|
774
|
+
trunk: z4.boolean().default(false),
|
|
775
|
+
includeDrafts: z4.boolean().default(false),
|
|
776
|
+
root: z4.string().optional(),
|
|
777
|
+
install: z4.union([z4.boolean(), z4.string(), z4.array(z4.string())]).default(true),
|
|
778
|
+
commitBeforeManualChecks: z4.boolean().default(false),
|
|
779
|
+
commitBeforePhaseEnd: z4.boolean().optional(),
|
|
780
|
+
copy: z4.array(z4.string()).default([
|
|
765
781
|
".env",
|
|
766
782
|
"settings.local.json",
|
|
767
783
|
".claude/settings.local.json"
|
|
768
784
|
])
|
|
769
785
|
}).optional(),
|
|
770
|
-
run:
|
|
771
|
-
subtasks:
|
|
772
|
-
|
|
773
|
-
title:
|
|
774
|
-
description:
|
|
786
|
+
run: z4.array(z4.union([runConfigSchema, runLinkSchema])).optional(),
|
|
787
|
+
subtasks: z4.array(
|
|
788
|
+
z4.strictObject({
|
|
789
|
+
title: z4.string(),
|
|
790
|
+
description: z4.string().optional()
|
|
775
791
|
})
|
|
776
792
|
).optional(),
|
|
777
793
|
transcript: transcriptConfigSchema.optional(),
|
|
778
|
-
cliReadVerbs:
|
|
779
|
-
cliHook:
|
|
780
|
-
blockNpmRun:
|
|
794
|
+
cliReadVerbs: z4.record(z4.string(), z4.array(z4.string())).optional(),
|
|
795
|
+
cliHook: z4.strictObject({
|
|
796
|
+
blockNpmRun: z4.boolean().default(true)
|
|
781
797
|
}).optional(),
|
|
782
|
-
dotnet:
|
|
783
|
-
inspect:
|
|
784
|
-
suppress:
|
|
798
|
+
dotnet: z4.strictObject({
|
|
799
|
+
inspect: z4.strictObject({
|
|
800
|
+
suppress: z4.array(z4.string()).default([])
|
|
785
801
|
}).default({ suppress: [] })
|
|
786
802
|
}).optional(),
|
|
787
|
-
litellm:
|
|
788
|
-
baseUrl:
|
|
789
|
-
apiKey: secretConfigValue(
|
|
803
|
+
litellm: z4.strictObject({
|
|
804
|
+
baseUrl: z4.string().optional(),
|
|
805
|
+
apiKey: secretConfigValue(z4.string()).optional()
|
|
790
806
|
}).optional(),
|
|
791
|
-
ravendb:
|
|
792
|
-
connections:
|
|
793
|
-
|
|
794
|
-
name:
|
|
795
|
-
url:
|
|
796
|
-
database:
|
|
797
|
-
apiKeyRef:
|
|
807
|
+
ravendb: z4.strictObject({
|
|
808
|
+
connections: z4.array(
|
|
809
|
+
z4.strictObject({
|
|
810
|
+
name: z4.string(),
|
|
811
|
+
url: z4.string(),
|
|
812
|
+
database: z4.string(),
|
|
813
|
+
apiKeyRef: z4.string()
|
|
798
814
|
})
|
|
799
815
|
).default([]),
|
|
800
|
-
defaultConnection:
|
|
816
|
+
defaultConnection: z4.string().optional()
|
|
801
817
|
}).optional(),
|
|
802
|
-
seq:
|
|
803
|
-
connections:
|
|
804
|
-
|
|
805
|
-
name:
|
|
806
|
-
url:
|
|
807
|
-
apiToken: secretConfigValue(
|
|
818
|
+
seq: z4.strictObject({
|
|
819
|
+
connections: z4.array(
|
|
820
|
+
z4.strictObject({
|
|
821
|
+
name: z4.string(),
|
|
822
|
+
url: z4.string(),
|
|
823
|
+
apiToken: secretConfigValue(z4.string())
|
|
808
824
|
})
|
|
809
825
|
).default([]),
|
|
810
|
-
defaultConnection:
|
|
826
|
+
defaultConnection: z4.string().optional()
|
|
811
827
|
}).optional(),
|
|
812
|
-
sql:
|
|
813
|
-
connections:
|
|
814
|
-
|
|
815
|
-
name:
|
|
816
|
-
server:
|
|
817
|
-
port:
|
|
818
|
-
user:
|
|
819
|
-
password: secretConfigValue(
|
|
820
|
-
database:
|
|
828
|
+
sql: z4.strictObject({
|
|
829
|
+
connections: z4.array(
|
|
830
|
+
z4.strictObject({
|
|
831
|
+
name: z4.string(),
|
|
832
|
+
server: z4.string(),
|
|
833
|
+
port: z4.number(),
|
|
834
|
+
user: z4.string(),
|
|
835
|
+
password: secretConfigValue(z4.string()),
|
|
836
|
+
database: z4.string()
|
|
821
837
|
})
|
|
822
838
|
).default([]),
|
|
823
|
-
defaultConnection:
|
|
839
|
+
defaultConnection: z4.string().optional()
|
|
824
840
|
}).optional(),
|
|
825
|
-
screenshot:
|
|
826
|
-
outputDir:
|
|
841
|
+
screenshot: z4.strictObject({
|
|
842
|
+
outputDir: z4.string().default("./screenshots")
|
|
827
843
|
}).default({ outputDir: "./screenshots" }),
|
|
828
|
-
sessions:
|
|
829
|
-
nodeName:
|
|
830
|
-
links:
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
])
|
|
840
|
-
).optional(),
|
|
841
|
-
linkVersionCheck: z3.enum(["block", "warn", "off"]).default("block"),
|
|
842
|
-
tailscaleServe: z3.boolean().default(true),
|
|
843
|
-
includeCommittedChanges: z3.boolean().default(true),
|
|
844
|
-
topBar: z3.boolean().default(true),
|
|
845
|
-
floatWaiting: z3.boolean().default(true),
|
|
846
|
-
floatWaitingAfterMs: z3.number().default(5e3),
|
|
847
|
-
maxLive: z3.number().default(24),
|
|
848
|
-
newSessionMode: z3.enum(["draft", "bug", "prompt", "design"]).default("draft")
|
|
844
|
+
sessions: z4.strictObject({
|
|
845
|
+
nodeName: z4.string().optional(),
|
|
846
|
+
links: z4.array(sessionLinkSchema).optional(),
|
|
847
|
+
linkVersionCheck: z4.enum(["block", "warn", "off"]).default("block"),
|
|
848
|
+
tailscaleServe: z4.boolean().default(true),
|
|
849
|
+
includeCommittedChanges: z4.boolean().default(true),
|
|
850
|
+
topBar: z4.boolean().default(true),
|
|
851
|
+
floatWaiting: z4.boolean().default(true),
|
|
852
|
+
floatWaitingAfterMs: z4.number().default(5e3),
|
|
853
|
+
maxLive: z4.number().default(24),
|
|
854
|
+
newSessionMode: z4.enum(["draft", "bug", "prompt", "design"]).default("draft")
|
|
849
855
|
}).optional(),
|
|
850
|
-
database:
|
|
851
|
-
url: secretConfigValue(
|
|
856
|
+
database: z4.strictObject({
|
|
857
|
+
url: secretConfigValue(z4.string()).optional()
|
|
852
858
|
}).default({}),
|
|
853
|
-
mermaid:
|
|
854
|
-
krokiUrl:
|
|
859
|
+
mermaid: z4.strictObject({
|
|
860
|
+
krokiUrl: z4.string().default("https://kroki.io")
|
|
855
861
|
}).default({ krokiUrl: "https://kroki.io" }),
|
|
856
|
-
miro:
|
|
857
|
-
extracts:
|
|
862
|
+
miro: z4.strictObject({
|
|
863
|
+
extracts: z4.record(z4.string(), miroExtractSchema).optional()
|
|
858
864
|
}).optional(),
|
|
859
|
-
news:
|
|
860
|
-
showInNav:
|
|
865
|
+
news: z4.strictObject({
|
|
866
|
+
showInNav: z4.boolean().default(false)
|
|
861
867
|
}).optional(),
|
|
862
|
-
next:
|
|
863
|
-
peers:
|
|
864
|
-
repos:
|
|
865
|
-
projects:
|
|
866
|
-
|
|
868
|
+
next: z4.strictObject({
|
|
869
|
+
peers: z4.array(z4.string()).optional(),
|
|
870
|
+
repos: z4.array(z4.string()).optional(),
|
|
871
|
+
projects: z4.array(
|
|
872
|
+
z4.string().regex(
|
|
867
873
|
/^[^/\s]+\/\d+$/,
|
|
868
874
|
"Use <owner>/<project number>, e.g. my-org/3"
|
|
869
875
|
)
|
|
870
876
|
).optional(),
|
|
871
|
-
pickStatuses:
|
|
872
|
-
excludeLabels:
|
|
873
|
-
excludeTypes:
|
|
877
|
+
pickStatuses: z4.array(z4.string()).optional(),
|
|
878
|
+
excludeLabels: z4.array(z4.string()).optional(),
|
|
879
|
+
excludeTypes: z4.array(z4.string()).optional()
|
|
874
880
|
}).optional(),
|
|
875
|
-
deny:
|
|
876
|
-
|
|
877
|
-
pattern:
|
|
878
|
-
message:
|
|
881
|
+
deny: z4.array(
|
|
882
|
+
z4.strictObject({
|
|
883
|
+
pattern: z4.string(),
|
|
884
|
+
message: z4.string()
|
|
879
885
|
})
|
|
880
886
|
).optional(),
|
|
881
|
-
forbiddenStrings:
|
|
882
|
-
|
|
883
|
-
file:
|
|
884
|
-
paths:
|
|
885
|
-
disallowed:
|
|
887
|
+
forbiddenStrings: z4.array(
|
|
888
|
+
z4.strictObject({
|
|
889
|
+
file: z4.string(),
|
|
890
|
+
paths: z4.array(z4.string()),
|
|
891
|
+
disallowed: z4.string()
|
|
886
892
|
})
|
|
887
893
|
).optional(),
|
|
888
|
-
sync:
|
|
889
|
-
autoConfirm:
|
|
894
|
+
sync: z4.strictObject({
|
|
895
|
+
autoConfirm: z4.boolean().default(false)
|
|
890
896
|
}).default({ autoConfirm: false }),
|
|
891
|
-
harness:
|
|
892
|
-
engine:
|
|
893
|
-
exposeCodexActions:
|
|
894
|
-
exposePiActions:
|
|
895
|
-
codexModel:
|
|
897
|
+
harness: z4.strictObject({
|
|
898
|
+
engine: z4.enum(["claude", "codex", "pi"]).default("claude"),
|
|
899
|
+
exposeCodexActions: z4.boolean().optional(),
|
|
900
|
+
exposePiActions: z4.boolean().optional(),
|
|
901
|
+
codexModel: z4.string().optional()
|
|
896
902
|
}).default({ engine: "claude" })
|
|
897
903
|
};
|
|
898
|
-
var repoConfigSchema =
|
|
899
|
-
var assistConfigSchema =
|
|
904
|
+
var repoConfigSchema = z4.strictObject(assistConfigShape).partial();
|
|
905
|
+
var assistConfigSchema = z4.strictObject({
|
|
900
906
|
...assistConfigShape,
|
|
901
|
-
repos:
|
|
907
|
+
repos: z4.record(z4.string(), repoConfigSchema).optional()
|
|
902
908
|
});
|
|
903
909
|
|
|
904
910
|
// src/shared/loadConfigFrom.ts
|
|
@@ -5071,52 +5077,52 @@ async function loadAllItems(orm, origin) {
|
|
|
5071
5077
|
import { readFileSync as readFileSync13 } from "fs";
|
|
5072
5078
|
|
|
5073
5079
|
// src/commands/backlog/types.ts
|
|
5074
|
-
import { z as
|
|
5075
|
-
var backlogStatusSchema =
|
|
5076
|
-
var backlogTypeSchema =
|
|
5077
|
-
var planTaskSchema =
|
|
5078
|
-
task:
|
|
5080
|
+
import { z as z5 } from "zod";
|
|
5081
|
+
var backlogStatusSchema = z5.enum(["todo", "in-progress", "done", "wontdo"]);
|
|
5082
|
+
var backlogTypeSchema = z5.enum(["story", "bug"]);
|
|
5083
|
+
var planTaskSchema = z5.object({
|
|
5084
|
+
task: z5.string()
|
|
5079
5085
|
}).strip();
|
|
5080
|
-
var planPhaseSchema =
|
|
5081
|
-
name:
|
|
5082
|
-
tasks:
|
|
5083
|
-
manualChecks:
|
|
5086
|
+
var planPhaseSchema = z5.strictObject({
|
|
5087
|
+
name: z5.string(),
|
|
5088
|
+
tasks: z5.array(planTaskSchema),
|
|
5089
|
+
manualChecks: z5.array(z5.string()).optional()
|
|
5084
5090
|
});
|
|
5085
|
-
var phaseUsageSchema =
|
|
5086
|
-
phaseIdx:
|
|
5087
|
-
tokensUp:
|
|
5088
|
-
tokensDown:
|
|
5089
|
-
activeMs:
|
|
5090
|
-
peakContextPct:
|
|
5091
|
+
var phaseUsageSchema = z5.strictObject({
|
|
5092
|
+
phaseIdx: z5.number(),
|
|
5093
|
+
tokensUp: z5.number(),
|
|
5094
|
+
tokensDown: z5.number(),
|
|
5095
|
+
activeMs: z5.number(),
|
|
5096
|
+
peakContextPct: z5.number()
|
|
5091
5097
|
});
|
|
5092
|
-
var phaseSessionSchema =
|
|
5093
|
-
phaseIdx:
|
|
5094
|
-
claudeSessionId:
|
|
5095
|
-
hostname:
|
|
5096
|
-
osUser:
|
|
5097
|
-
createdAt:
|
|
5098
|
+
var phaseSessionSchema = z5.strictObject({
|
|
5099
|
+
phaseIdx: z5.number(),
|
|
5100
|
+
claudeSessionId: z5.string(),
|
|
5101
|
+
hostname: z5.string(),
|
|
5102
|
+
osUser: z5.string(),
|
|
5103
|
+
createdAt: z5.string().optional()
|
|
5098
5104
|
});
|
|
5099
|
-
var phaseUsageTotalSchema =
|
|
5100
|
-
tokensUp:
|
|
5101
|
-
tokensDown:
|
|
5102
|
-
activeMs:
|
|
5103
|
-
peakContextPct:
|
|
5105
|
+
var phaseUsageTotalSchema = z5.strictObject({
|
|
5106
|
+
tokensUp: z5.number(),
|
|
5107
|
+
tokensDown: z5.number(),
|
|
5108
|
+
activeMs: z5.number(),
|
|
5109
|
+
peakContextPct: z5.number()
|
|
5104
5110
|
});
|
|
5105
|
-
var subtaskStatusSchema =
|
|
5106
|
-
var subtaskSchema =
|
|
5107
|
-
title:
|
|
5108
|
-
description:
|
|
5111
|
+
var subtaskStatusSchema = z5.enum(["todo", "in-progress", "done"]);
|
|
5112
|
+
var subtaskSchema = z5.strictObject({
|
|
5113
|
+
title: z5.string(),
|
|
5114
|
+
description: z5.string().optional(),
|
|
5109
5115
|
status: subtaskStatusSchema.default("todo")
|
|
5110
5116
|
});
|
|
5111
|
-
var backlogCommentTypeSchema =
|
|
5112
|
-
var backlogCommentSchema =
|
|
5113
|
-
id:
|
|
5114
|
-
text:
|
|
5115
|
-
phase:
|
|
5116
|
-
timestamp:
|
|
5117
|
+
var backlogCommentTypeSchema = z5.enum(["comment", "summary"]);
|
|
5118
|
+
var backlogCommentSchema = z5.strictObject({
|
|
5119
|
+
id: z5.number().optional(),
|
|
5120
|
+
text: z5.string(),
|
|
5121
|
+
phase: z5.number().optional(),
|
|
5122
|
+
timestamp: z5.string(),
|
|
5117
5123
|
type: backlogCommentTypeSchema
|
|
5118
5124
|
});
|
|
5119
|
-
var gitRefKindSchema =
|
|
5125
|
+
var gitRefKindSchema = z5.enum([
|
|
5120
5126
|
"branch",
|
|
5121
5127
|
"commit",
|
|
5122
5128
|
"commit-parent",
|
|
@@ -5124,41 +5130,41 @@ var gitRefKindSchema = z4.enum([
|
|
|
5124
5130
|
"slack",
|
|
5125
5131
|
"session"
|
|
5126
5132
|
]);
|
|
5127
|
-
var gitRefSchema =
|
|
5133
|
+
var gitRefSchema = z5.strictObject({
|
|
5128
5134
|
kind: gitRefKindSchema,
|
|
5129
|
-
ref:
|
|
5130
|
-
title:
|
|
5131
|
-
url:
|
|
5132
|
-
state:
|
|
5133
|
-
createdAt:
|
|
5135
|
+
ref: z5.string(),
|
|
5136
|
+
title: z5.string().optional(),
|
|
5137
|
+
url: z5.string().optional(),
|
|
5138
|
+
state: z5.string().optional(),
|
|
5139
|
+
createdAt: z5.string().optional()
|
|
5134
5140
|
});
|
|
5135
|
-
var backlogLinkTypeSchema =
|
|
5136
|
-
var backlogLinkSchema =
|
|
5141
|
+
var backlogLinkTypeSchema = z5.enum(["relates-to", "depends-on"]);
|
|
5142
|
+
var backlogLinkSchema = z5.strictObject({
|
|
5137
5143
|
type: backlogLinkTypeSchema,
|
|
5138
|
-
targetId:
|
|
5144
|
+
targetId: z5.number()
|
|
5139
5145
|
});
|
|
5140
|
-
var backlogItemSchema =
|
|
5141
|
-
id:
|
|
5146
|
+
var backlogItemSchema = z5.strictObject({
|
|
5147
|
+
id: z5.number(),
|
|
5142
5148
|
type: backlogTypeSchema.default("story"),
|
|
5143
|
-
name:
|
|
5144
|
-
description:
|
|
5145
|
-
acceptanceCriteria:
|
|
5146
|
-
plan:
|
|
5147
|
-
currentPhase:
|
|
5148
|
-
starred:
|
|
5149
|
+
name: z5.string(),
|
|
5150
|
+
description: z5.string().optional(),
|
|
5151
|
+
acceptanceCriteria: z5.array(z5.string()),
|
|
5152
|
+
plan: z5.array(planPhaseSchema).optional(),
|
|
5153
|
+
currentPhase: z5.number().optional(),
|
|
5154
|
+
starred: z5.boolean().default(false),
|
|
5149
5155
|
status: backlogStatusSchema,
|
|
5150
|
-
comments:
|
|
5151
|
-
subtasks:
|
|
5152
|
-
links:
|
|
5153
|
-
phaseUsage:
|
|
5154
|
-
phaseSessions:
|
|
5156
|
+
comments: z5.array(backlogCommentSchema).optional(),
|
|
5157
|
+
subtasks: z5.array(subtaskSchema).optional(),
|
|
5158
|
+
links: z5.array(backlogLinkSchema).optional(),
|
|
5159
|
+
phaseUsage: z5.array(phaseUsageSchema).optional(),
|
|
5160
|
+
phaseSessions: z5.array(phaseSessionSchema).optional(),
|
|
5155
5161
|
usageTotal: phaseUsageTotalSchema.optional(),
|
|
5156
|
-
gitRefs:
|
|
5157
|
-
origin:
|
|
5158
|
-
jiraKey:
|
|
5159
|
-
githubIssue:
|
|
5162
|
+
gitRefs: z5.array(gitRefSchema).optional(),
|
|
5163
|
+
origin: z5.string().optional(),
|
|
5164
|
+
jiraKey: z5.string().optional(),
|
|
5165
|
+
githubIssue: z5.string().optional()
|
|
5160
5166
|
});
|
|
5161
|
-
var backlogFileSchema =
|
|
5167
|
+
var backlogFileSchema = z5.array(backlogItemSchema);
|
|
5162
5168
|
|
|
5163
5169
|
// src/commands/backlog/parseBacklogJsonl.ts
|
|
5164
5170
|
function parseBacklogJsonl(path106) {
|
|
@@ -6525,7 +6531,7 @@ ${issues}`);
|
|
|
6525
6531
|
}
|
|
6526
6532
|
|
|
6527
6533
|
// src/commands/backlog/propose/proposedItemSchema.ts
|
|
6528
|
-
import { z as
|
|
6534
|
+
import { z as z6 } from "zod";
|
|
6529
6535
|
|
|
6530
6536
|
// src/commands/backlog/buildCommentLines.ts
|
|
6531
6537
|
function buildCommentLines(comments3) {
|
|
@@ -6677,20 +6683,20 @@ function buildPhasePrompt(item, phaseNumber, phase) {
|
|
|
6677
6683
|
}
|
|
6678
6684
|
|
|
6679
6685
|
// src/commands/backlog/propose/proposedItemSchema.ts
|
|
6680
|
-
var proposedPhaseSchema =
|
|
6681
|
-
name:
|
|
6686
|
+
var proposedPhaseSchema = z6.strictObject({
|
|
6687
|
+
name: z6.string().trim().min(1, "phase name is required").refine(
|
|
6682
6688
|
(name) => name.toLowerCase() !== REVIEW_PHASE_NAME.toLowerCase(),
|
|
6683
6689
|
`"${REVIEW_PHASE_NAME}" is owned by the runner and appended to every plan automatically \u2014 remove this phase`
|
|
6684
6690
|
),
|
|
6685
|
-
tasks:
|
|
6686
|
-
manualChecks:
|
|
6691
|
+
tasks: z6.array(z6.string().trim().min(1)).min(1, "a phase needs at least one task"),
|
|
6692
|
+
manualChecks: z6.array(z6.string().trim().min(1)).default([])
|
|
6687
6693
|
});
|
|
6688
|
-
var proposedItemSchema =
|
|
6689
|
-
name:
|
|
6690
|
-
type:
|
|
6691
|
-
description:
|
|
6692
|
-
acceptanceCriteria:
|
|
6693
|
-
phases:
|
|
6694
|
+
var proposedItemSchema = z6.strictObject({
|
|
6695
|
+
name: z6.string().trim().min(1, "name is required"),
|
|
6696
|
+
type: z6.enum(["story", "bug"]),
|
|
6697
|
+
description: z6.string().optional(),
|
|
6698
|
+
acceptanceCriteria: z6.array(z6.string().trim().min(1)).default([]),
|
|
6699
|
+
phases: z6.array(proposedPhaseSchema).default([])
|
|
6694
6700
|
});
|
|
6695
6701
|
|
|
6696
6702
|
// src/commands/backlog/propose/readProposedItem.ts
|
|
@@ -8215,18 +8221,18 @@ async function persistPhaseSessionId(itemId2, phaseIdx, claudeSessionId) {
|
|
|
8215
8221
|
import { mkdirSync as mkdirSync9, readFileSync as readFileSync19, rmSync as rmSync2, writeFileSync as writeFileSync20 } from "fs";
|
|
8216
8222
|
import { homedir as homedir11 } from "os";
|
|
8217
8223
|
import { dirname as dirname18, join as join30 } from "path";
|
|
8218
|
-
import { z as
|
|
8219
|
-
var activitySchema =
|
|
8220
|
-
kind:
|
|
8221
|
-
harness:
|
|
8222
|
-
name:
|
|
8223
|
-
itemId:
|
|
8224
|
-
itemName:
|
|
8225
|
-
phase:
|
|
8226
|
-
phaseName:
|
|
8227
|
-
totalPhases:
|
|
8228
|
-
claudeSessionId:
|
|
8229
|
-
startedAt:
|
|
8224
|
+
import { z as z7 } from "zod";
|
|
8225
|
+
var activitySchema = z7.object({
|
|
8226
|
+
kind: z7.enum(["command", "backlog"]),
|
|
8227
|
+
harness: z7.enum(["claude", "codex", "pi"]).optional(),
|
|
8228
|
+
name: z7.string().optional(),
|
|
8229
|
+
itemId: z7.number().optional(),
|
|
8230
|
+
itemName: z7.string().optional(),
|
|
8231
|
+
phase: z7.number().optional(),
|
|
8232
|
+
phaseName: z7.string().optional(),
|
|
8233
|
+
totalPhases: z7.number().optional(),
|
|
8234
|
+
claudeSessionId: z7.string().optional(),
|
|
8235
|
+
startedAt: z7.number()
|
|
8230
8236
|
});
|
|
8231
8237
|
function activityPath(sessionId) {
|
|
8232
8238
|
return join30(homedir11(), ".assist", "activity", `activity-${sessionId}.json`);
|
|
@@ -10243,9 +10249,9 @@ async function update(id, options2) {
|
|
|
10243
10249
|
import chalk102 from "chalk";
|
|
10244
10250
|
|
|
10245
10251
|
// src/commands/backlog/updatePlan/planUpdateSchema.ts
|
|
10246
|
-
import { z as
|
|
10247
|
-
var planUpdateSchema =
|
|
10248
|
-
phases:
|
|
10252
|
+
import { z as z8 } from "zod";
|
|
10253
|
+
var planUpdateSchema = z8.strictObject({
|
|
10254
|
+
phases: z8.array(proposedPhaseSchema).min(1, "a plan needs at least one phase")
|
|
10249
10255
|
});
|
|
10250
10256
|
|
|
10251
10257
|
// src/commands/backlog/updatePlan/readPlanUpdate.ts
|
|
@@ -12997,8 +13003,8 @@ var seqConfigHelp = [
|
|
|
12997
13003
|
var nodesConfigHelp = [
|
|
12998
13004
|
{
|
|
12999
13005
|
key: "sessions.links",
|
|
13000
|
-
setter: "assist sessions nodes link <name>
|
|
13001
|
-
note: "linked nodes whose sessions merge into this node's web UI, each
|
|
13006
|
+
setter: "assist sessions nodes link <name> --tailscale <host> --port <port> (or a peer <url>)",
|
|
13007
|
+
note: "linked nodes whose sessions merge into this node's web UI, each dialled at its url (a Tailscale https://<host>.<tailnet>.ts.net:<port> url, or any direct url); each name must match the peer's sessions.nodeName"
|
|
13002
13008
|
},
|
|
13003
13009
|
{
|
|
13004
13010
|
key: "sessions.linkVersionCheck",
|
|
@@ -15007,21 +15013,8 @@ async function prList(req, res) {
|
|
|
15007
15013
|
}
|
|
15008
15014
|
|
|
15009
15015
|
// src/commands/sessions/shared/loadLinkSpecs.ts
|
|
15010
|
-
var TUNNEL_PORT_BASE = 43e3;
|
|
15011
|
-
function defaultTunnelPort(port) {
|
|
15012
|
-
return TUNNEL_PORT_BASE + port % 1e3;
|
|
15013
|
-
}
|
|
15014
|
-
function toLinkSpec(link3) {
|
|
15015
|
-
if ("url" in link3) return { name: link3.name, url: link3.url };
|
|
15016
|
-
const localPort = link3.localPort ?? defaultTunnelPort(link3.port);
|
|
15017
|
-
return {
|
|
15018
|
-
name: link3.name,
|
|
15019
|
-
url: `http://127.0.0.1:${localPort}`,
|
|
15020
|
-
ssh: { alias: link3.ssh, port: link3.port, localPort }
|
|
15021
|
-
};
|
|
15022
|
-
}
|
|
15023
15016
|
function loadLinkSpecs() {
|
|
15024
|
-
return
|
|
15017
|
+
return loadConfig().sessions?.links ?? [];
|
|
15025
15018
|
}
|
|
15026
15019
|
function findLinkSpec(name) {
|
|
15027
15020
|
return loadLinkSpecs().find((spec) => spec.name === name);
|
|
@@ -25275,36 +25268,36 @@ function stringOrUndefined(value) {
|
|
|
25275
25268
|
}
|
|
25276
25269
|
|
|
25277
25270
|
// src/commands/sessions/daemon/persistedSessionSchema.ts
|
|
25278
|
-
import { z as
|
|
25279
|
-
var persistedSessionSchema =
|
|
25280
|
-
id:
|
|
25281
|
-
name:
|
|
25282
|
-
title:
|
|
25283
|
-
generatedTitle:
|
|
25284
|
-
subtitle:
|
|
25285
|
-
commandType:
|
|
25286
|
-
harness:
|
|
25287
|
-
status:
|
|
25288
|
-
cwd:
|
|
25289
|
-
startedAt:
|
|
25290
|
-
runningMs:
|
|
25291
|
-
claudeSessionId:
|
|
25292
|
-
harnessSessionId:
|
|
25293
|
-
initialPrompt:
|
|
25294
|
-
runName:
|
|
25295
|
-
runArgs:
|
|
25296
|
-
assistArgs:
|
|
25271
|
+
import { z as z9 } from "zod";
|
|
25272
|
+
var persistedSessionSchema = z9.object({
|
|
25273
|
+
id: z9.string().optional(),
|
|
25274
|
+
name: z9.string(),
|
|
25275
|
+
title: z9.string().optional(),
|
|
25276
|
+
generatedTitle: z9.string().optional(),
|
|
25277
|
+
subtitle: z9.string().optional(),
|
|
25278
|
+
commandType: z9.enum(["claude", "run", "assist"]),
|
|
25279
|
+
harness: z9.enum(["claude", "codex", "pi"]).optional(),
|
|
25280
|
+
status: z9.enum(["running", "waiting", "done", "error", "stopped"]).optional(),
|
|
25281
|
+
cwd: z9.string(),
|
|
25282
|
+
startedAt: z9.number(),
|
|
25283
|
+
runningMs: z9.number().optional(),
|
|
25284
|
+
claudeSessionId: z9.string().optional(),
|
|
25285
|
+
harnessSessionId: z9.string().optional(),
|
|
25286
|
+
initialPrompt: z9.string().optional(),
|
|
25287
|
+
runName: z9.string().optional(),
|
|
25288
|
+
runArgs: z9.array(z9.string()).optional(),
|
|
25289
|
+
assistArgs: z9.array(z9.string()).optional(),
|
|
25297
25290
|
activity: activitySchema.optional(),
|
|
25298
|
-
starred:
|
|
25299
|
-
watcher:
|
|
25300
|
-
design:
|
|
25301
|
-
auto:
|
|
25302
|
-
autoRun:
|
|
25303
|
-
autoAdvance:
|
|
25304
|
-
reviewStarted:
|
|
25305
|
-
launchedFrom:
|
|
25306
|
-
interrupted:
|
|
25307
|
-
undurable:
|
|
25291
|
+
starred: z9.boolean().optional(),
|
|
25292
|
+
watcher: z9.boolean().optional(),
|
|
25293
|
+
design: z9.boolean().optional(),
|
|
25294
|
+
auto: z9.boolean().optional(),
|
|
25295
|
+
autoRun: z9.boolean().optional(),
|
|
25296
|
+
autoAdvance: z9.boolean().optional(),
|
|
25297
|
+
reviewStarted: z9.boolean().optional(),
|
|
25298
|
+
launchedFrom: z9.string().optional(),
|
|
25299
|
+
interrupted: z9.object({ reason: z9.string(), at: z9.number() }).optional(),
|
|
25300
|
+
undurable: z9.object({ reason: z9.string(), removesTree: z9.boolean().optional() }).optional()
|
|
25308
25301
|
});
|
|
25309
25302
|
|
|
25310
25303
|
// src/commands/sessions/daemon/toPersistedSession.ts
|
|
@@ -38177,16 +38170,16 @@ function selectPassages(sources, selection) {
|
|
|
38177
38170
|
}
|
|
38178
38171
|
|
|
38179
38172
|
// src/commands/transcript/selectionSchema.ts
|
|
38180
|
-
import { z as
|
|
38181
|
-
var selectionSchema =
|
|
38182
|
-
keep:
|
|
38183
|
-
|
|
38184
|
-
file:
|
|
38185
|
-
from:
|
|
38186
|
-
to:
|
|
38173
|
+
import { z as z10 } from "zod";
|
|
38174
|
+
var selectionSchema = z10.strictObject({
|
|
38175
|
+
keep: z10.array(
|
|
38176
|
+
z10.strictObject({
|
|
38177
|
+
file: z10.string().trim().min(1, "file is required"),
|
|
38178
|
+
from: z10.string().trim().min(1, "from is required"),
|
|
38179
|
+
to: z10.string().trim().min(1, "to is required")
|
|
38187
38180
|
})
|
|
38188
38181
|
).min(1, "a selection needs at least one keep range"),
|
|
38189
|
-
removed:
|
|
38182
|
+
removed: z10.array(z10.string().trim().min(1)).default([])
|
|
38190
38183
|
});
|
|
38191
38184
|
|
|
38192
38185
|
// src/commands/transcript/widenAudienceInText.ts
|
|
@@ -40228,14 +40221,6 @@ function registerRun(program2) {
|
|
|
40228
40221
|
|
|
40229
40222
|
// src/commands/sessions/nodes/formatLink.ts
|
|
40230
40223
|
import chalk253 from "chalk";
|
|
40231
|
-
|
|
40232
|
-
// src/commands/sessions/daemon/links/describeTarget.ts
|
|
40233
|
-
function describeTarget({ url, ssh }) {
|
|
40234
|
-
if (!ssh) return `direct ${url}`;
|
|
40235
|
-
return `ssh ${ssh.alias}:${ssh.port} via 127.0.0.1:${ssh.localPort}`;
|
|
40236
|
-
}
|
|
40237
|
-
|
|
40238
|
-
// src/commands/sessions/nodes/formatLink.ts
|
|
40239
40224
|
var STATE_COLOURS = {
|
|
40240
40225
|
connected: chalk253.green,
|
|
40241
40226
|
connecting: chalk253.yellow,
|
|
@@ -40247,7 +40232,7 @@ function formatLink(link3) {
|
|
|
40247
40232
|
const peer = link3.peerVersion ? ` peer ${link3.peerVersion}` : "";
|
|
40248
40233
|
const error = link3.error ? `
|
|
40249
40234
|
${chalk253.dim(`last error${link3.errorAt ? ` ${link3.errorAt}` : ""}: ${link3.error}`)}` : "";
|
|
40250
|
-
return ` ${link3.name} ${colour(link3.state)} ${
|
|
40235
|
+
return ` ${link3.name} ${colour(link3.state)} ${link3.url}${peer}${error}`;
|
|
40251
40236
|
}
|
|
40252
40237
|
|
|
40253
40238
|
// src/commands/sessions/daemon/listDaemonPids.ts
|
|
@@ -40479,9 +40464,9 @@ function createAutoExit(exit, graceMs = DEFAULT_GRACE_MS) {
|
|
|
40479
40464
|
}
|
|
40480
40465
|
|
|
40481
40466
|
// src/commands/sessions/daemon/loadActiveSelection.ts
|
|
40482
|
-
import { z as
|
|
40467
|
+
import { z as z11 } from "zod";
|
|
40483
40468
|
var ACTIVE_FILE = "active.json";
|
|
40484
|
-
var activeSelectionSchema =
|
|
40469
|
+
var activeSelectionSchema = z11.record(z11.string(), z11.string());
|
|
40485
40470
|
function loadActiveSelection() {
|
|
40486
40471
|
const parsed = activeSelectionSchema.safeParse(
|
|
40487
40472
|
loadJson(ACTIVE_FILE)
|
|
@@ -44144,10 +44129,10 @@ function restoreAllSessions(spawner, sessions, notify2) {
|
|
|
44144
44129
|
|
|
44145
44130
|
// src/commands/sessions/daemon/retrySession.ts
|
|
44146
44131
|
function retrySession(session, clients, onStatusChange) {
|
|
44147
|
-
const
|
|
44148
|
-
if (!
|
|
44132
|
+
const spawn10 = respawnThunk(session);
|
|
44133
|
+
if (!spawn10) return false;
|
|
44149
44134
|
const respawn = () => {
|
|
44150
|
-
respawnSession(session,
|
|
44135
|
+
respawnSession(session, spawn10, "running", clients, onStatusChange);
|
|
44151
44136
|
daemonLog(`session ${session.id} retried: ${session.name}`);
|
|
44152
44137
|
};
|
|
44153
44138
|
const pty2 = session.pty;
|
|
@@ -44721,134 +44706,6 @@ async function selfUpdatePeer(url) {
|
|
|
44721
44706
|
throw new Error(body.error ?? `self-update responded ${response.status}`);
|
|
44722
44707
|
}
|
|
44723
44708
|
|
|
44724
|
-
// src/commands/sessions/daemon/links/SshTunnel.ts
|
|
44725
|
-
import { createInterface as createInterface10 } from "readline";
|
|
44726
|
-
import { setTimeout as delay2 } from "timers/promises";
|
|
44727
|
-
|
|
44728
|
-
// src/commands/sessions/daemon/links/killOrphanOnDaemonExit.ts
|
|
44729
|
-
var liveChildren = /* @__PURE__ */ new Set();
|
|
44730
|
-
var exitHookInstalled = false;
|
|
44731
|
-
function killOrphanOnDaemonExit(child) {
|
|
44732
|
-
liveChildren.add(child);
|
|
44733
|
-
child.once("exit", () => liveChildren.delete(child));
|
|
44734
|
-
if (exitHookInstalled) return;
|
|
44735
|
-
exitHookInstalled = true;
|
|
44736
|
-
process.once("exit", () => {
|
|
44737
|
-
for (const live of liveChildren) live.kill();
|
|
44738
|
-
});
|
|
44739
|
-
}
|
|
44740
|
-
|
|
44741
|
-
// src/commands/sessions/daemon/links/sshTunnelArgs.ts
|
|
44742
|
-
function sshTunnelArgs({ alias, port, localPort }) {
|
|
44743
|
-
return [
|
|
44744
|
-
"-N",
|
|
44745
|
-
"-o",
|
|
44746
|
-
"BatchMode=yes",
|
|
44747
|
-
"-o",
|
|
44748
|
-
"ExitOnForwardFailure=yes",
|
|
44749
|
-
"-o",
|
|
44750
|
-
"ServerAliveInterval=15",
|
|
44751
|
-
"-o",
|
|
44752
|
-
"ServerAliveCountMax=3",
|
|
44753
|
-
"-L",
|
|
44754
|
-
`${localPort}:127.0.0.1:${port}`,
|
|
44755
|
-
alias
|
|
44756
|
-
];
|
|
44757
|
-
}
|
|
44758
|
-
|
|
44759
|
-
// src/commands/sessions/daemon/links/SshTunnelIo.ts
|
|
44760
|
-
import { spawn as spawn10 } from "child_process";
|
|
44761
|
-
|
|
44762
|
-
// src/commands/sessions/shared/portAccepts.ts
|
|
44763
|
-
import { connect as connect3 } from "net";
|
|
44764
|
-
function portAccepts(port, timeoutMs = 1e3) {
|
|
44765
|
-
return new Promise((resolve26) => {
|
|
44766
|
-
const socket = connect3({ host: "127.0.0.1", port });
|
|
44767
|
-
const settle = (ok) => {
|
|
44768
|
-
socket.destroy();
|
|
44769
|
-
resolve26(ok);
|
|
44770
|
-
};
|
|
44771
|
-
socket.setTimeout(timeoutMs, () => settle(false));
|
|
44772
|
-
socket.once("connect", () => settle(true));
|
|
44773
|
-
socket.once("error", () => settle(false));
|
|
44774
|
-
});
|
|
44775
|
-
}
|
|
44776
|
-
|
|
44777
|
-
// src/commands/sessions/daemon/links/SshTunnelIo.ts
|
|
44778
|
-
var defaultSshTunnelIo = {
|
|
44779
|
-
spawn: (args) => spawn10("ssh", args, {
|
|
44780
|
-
stdio: ["ignore", "ignore", "pipe"],
|
|
44781
|
-
windowsHide: true
|
|
44782
|
-
}),
|
|
44783
|
-
accepts: (port) => portAccepts(port),
|
|
44784
|
-
bindTimeoutMs: 15e3,
|
|
44785
|
-
pollMs: 200
|
|
44786
|
-
};
|
|
44787
|
-
|
|
44788
|
-
// src/commands/sessions/daemon/links/SshTunnel.ts
|
|
44789
|
-
var SshTunnel = class {
|
|
44790
|
-
constructor(name, target, io = defaultSshTunnelIo) {
|
|
44791
|
-
this.name = name;
|
|
44792
|
-
this.target = target;
|
|
44793
|
-
this.io = io;
|
|
44794
|
-
}
|
|
44795
|
-
child;
|
|
44796
|
-
exitReason = "";
|
|
44797
|
-
lastStderr = "";
|
|
44798
|
-
async ready() {
|
|
44799
|
-
if (!this.child) this.start();
|
|
44800
|
-
await this.waitBound(this.child);
|
|
44801
|
-
}
|
|
44802
|
-
dispose() {
|
|
44803
|
-
const child = this.child;
|
|
44804
|
-
this.child = void 0;
|
|
44805
|
-
if (!child) return;
|
|
44806
|
-
daemonLog(`link ${this.name} tunnel: stopping ssh`);
|
|
44807
|
-
child.kill();
|
|
44808
|
-
}
|
|
44809
|
-
start() {
|
|
44810
|
-
const args = sshTunnelArgs(this.target);
|
|
44811
|
-
daemonLog(`link ${this.name} tunnel: spawning ssh ${args.join(" ")}`);
|
|
44812
|
-
const child = this.io.spawn(args);
|
|
44813
|
-
this.child = child;
|
|
44814
|
-
this.lastStderr = "";
|
|
44815
|
-
killOrphanOnDaemonExit(child);
|
|
44816
|
-
if (child.stderr)
|
|
44817
|
-
createInterface10({ input: child.stderr }).on("line", (line) => {
|
|
44818
|
-
this.lastStderr = line;
|
|
44819
|
-
daemonLog(`link ${this.name} ssh: ${line}`);
|
|
44820
|
-
});
|
|
44821
|
-
child.once("error", (error) => this.onExit(child, error.message));
|
|
44822
|
-
child.once(
|
|
44823
|
-
"exit",
|
|
44824
|
-
(code, signal) => this.onExit(child, signal ? `signal ${signal}` : `code ${code}`)
|
|
44825
|
-
);
|
|
44826
|
-
}
|
|
44827
|
-
onExit(child, reason4) {
|
|
44828
|
-
if (this.child !== child) return;
|
|
44829
|
-
this.child = void 0;
|
|
44830
|
-
this.exitReason = this.lastStderr ? `${reason4}: ${this.lastStderr}` : reason4;
|
|
44831
|
-
daemonLog(`link ${this.name} tunnel: ssh exited (${this.exitReason})`);
|
|
44832
|
-
}
|
|
44833
|
-
async waitBound(child) {
|
|
44834
|
-
const { alias, localPort } = this.target;
|
|
44835
|
-
const deadline = Date.now() + this.io.bindTimeoutMs;
|
|
44836
|
-
while (Date.now() < deadline) {
|
|
44837
|
-
if (this.child !== child)
|
|
44838
|
-
throw new Error(`ssh tunnel to ${alias} exited (${this.exitReason})`);
|
|
44839
|
-
if (await this.io.accepts(localPort)) return;
|
|
44840
|
-
await delay2(this.io.pollMs);
|
|
44841
|
-
}
|
|
44842
|
-
this.dispose();
|
|
44843
|
-
throw new Error(
|
|
44844
|
-
`ssh tunnel to ${alias} did not bind 127.0.0.1:${localPort} within ${this.io.bindTimeoutMs / 1e3}s`
|
|
44845
|
-
);
|
|
44846
|
-
}
|
|
44847
|
-
};
|
|
44848
|
-
|
|
44849
|
-
// src/commands/sessions/daemon/links/sshTunnelFor.ts
|
|
44850
|
-
var sshTunnelFor = (spec) => spec.ssh ? new SshTunnel(spec.name, spec.ssh) : void 0;
|
|
44851
|
-
|
|
44852
44709
|
// src/commands/sessions/daemon/links/linkDeps.ts
|
|
44853
44710
|
function linkDeps(options2, callbacks) {
|
|
44854
44711
|
return {
|
|
@@ -44866,7 +44723,6 @@ function linkDeps(options2, callbacks) {
|
|
|
44866
44723
|
callbacks.onHistoryChanged
|
|
44867
44724
|
),
|
|
44868
44725
|
transport: options2.transport ?? connectLinkWebSocket,
|
|
44869
|
-
tunnel: options2.tunnel ?? sshTunnelFor,
|
|
44870
44726
|
heal: options2.heal ?? selfUpdatePeer,
|
|
44871
44727
|
reconnectMs: options2.reconnectMs ?? 3e3,
|
|
44872
44728
|
blockedRetryMs: options2.blockedRetryMs ?? 6e4,
|
|
@@ -44973,7 +44829,6 @@ function createLinkContext(spec, deps2) {
|
|
|
44973
44829
|
deps: deps2,
|
|
44974
44830
|
relay: createRelayState(spec.name, deps2),
|
|
44975
44831
|
breaker: new LaunchCircuitBreaker(`link ${spec.name} ws`),
|
|
44976
|
-
tunnel: deps2.tunnel(spec),
|
|
44977
44832
|
socket: null,
|
|
44978
44833
|
greeted: false,
|
|
44979
44834
|
state: "disconnected",
|
|
@@ -44992,7 +44847,6 @@ function describeLink(ctx) {
|
|
|
44992
44847
|
return {
|
|
44993
44848
|
name: ctx.spec.name,
|
|
44994
44849
|
url: ctx.spec.url,
|
|
44995
|
-
ssh: ctx.spec.ssh,
|
|
44996
44850
|
state: ctx.state,
|
|
44997
44851
|
error: ctx.blockedMessage ?? ctx.lastError?.message,
|
|
44998
44852
|
errorAt: ctx.lastError?.at,
|
|
@@ -45092,16 +44946,16 @@ function linkHealRefusal(node, peerVersion, healAttempted) {
|
|
|
45092
44946
|
}
|
|
45093
44947
|
|
|
45094
44948
|
// src/commands/sessions/daemon/links/scheduleReconnect.ts
|
|
45095
|
-
function armReconnect(ctx,
|
|
44949
|
+
function armReconnect(ctx, delay2) {
|
|
45096
44950
|
clearTimeout(ctx.reconnectTimer);
|
|
45097
|
-
ctx.reconnectTimer = setTimeout(ctx.connect,
|
|
44951
|
+
ctx.reconnectTimer = setTimeout(ctx.connect, delay2);
|
|
45098
44952
|
ctx.reconnectTimer.unref?.();
|
|
45099
44953
|
}
|
|
45100
44954
|
function scheduleReconnect2(ctx) {
|
|
45101
44955
|
if (ctx.disposed) return;
|
|
45102
44956
|
if (ctx.blockedMessage) return armReconnect(ctx, ctx.deps.blockedRetryMs);
|
|
45103
|
-
const
|
|
45104
|
-
armReconnect(ctx,
|
|
44957
|
+
const delay2 = ctx.breaker.tripped() ? ctx.breaker.remainingMs() : ctx.deps.reconnectMs;
|
|
44958
|
+
armReconnect(ctx, delay2);
|
|
45105
44959
|
}
|
|
45106
44960
|
function reconnectNow(ctx) {
|
|
45107
44961
|
ctx.breaker.clear();
|
|
@@ -45365,8 +45219,6 @@ async function openLink(ctx) {
|
|
|
45365
45219
|
if (ctx.breaker.tripped()) return scheduleReconnect2(ctx);
|
|
45366
45220
|
if (!ctx.blockedMessage) setLinkState(ctx, "connecting");
|
|
45367
45221
|
try {
|
|
45368
|
-
await ctx.tunnel?.ready();
|
|
45369
|
-
if (ctx.disposed) return;
|
|
45370
45222
|
daemonLog(`link ${ctx.spec.name} ws: connecting to ${ctx.spec.url}`);
|
|
45371
45223
|
const socket = await ctx.deps.transport(ctx.spec.url, {
|
|
45372
45224
|
onLine: guardLinkCallback(
|
|
@@ -45446,18 +45298,14 @@ var NodeLink = class {
|
|
|
45446
45298
|
this.ctx.disposed = true;
|
|
45447
45299
|
clearTimeout(this.ctx.reconnectTimer);
|
|
45448
45300
|
disconnectLink(this.ctx);
|
|
45449
|
-
this.ctx.tunnel?.dispose();
|
|
45450
45301
|
}
|
|
45451
45302
|
};
|
|
45452
45303
|
|
|
45453
45304
|
// src/commands/sessions/daemon/links/reconcileLinks.ts
|
|
45454
|
-
function sameTarget(wanted, current) {
|
|
45455
|
-
return wanted?.url === current.url && JSON.stringify(wanted.ssh) === JSON.stringify(current.ssh);
|
|
45456
|
-
}
|
|
45457
45305
|
function reconcileLinks(links2, specs, create) {
|
|
45458
45306
|
const wanted = new Map(specs.map((spec) => [spec.name, spec]));
|
|
45459
45307
|
for (const [name, link3] of links2) {
|
|
45460
|
-
if (
|
|
45308
|
+
if (wanted.get(name)?.url === link3.spec.url) {
|
|
45461
45309
|
link3.unlatch();
|
|
45462
45310
|
continue;
|
|
45463
45311
|
}
|
|
@@ -45467,7 +45315,7 @@ function reconcileLinks(links2, specs, create) {
|
|
|
45467
45315
|
}
|
|
45468
45316
|
for (const spec of specs) {
|
|
45469
45317
|
if (links2.has(spec.name)) continue;
|
|
45470
|
-
daemonLog(`link ${spec.name}: added (${
|
|
45318
|
+
daemonLog(`link ${spec.name}: added (${spec.url})`);
|
|
45471
45319
|
const link3 = create(spec);
|
|
45472
45320
|
links2.set(spec.name, link3);
|
|
45473
45321
|
link3.start();
|
|
@@ -45997,7 +45845,7 @@ function exitAfterFlush(code) {
|
|
|
45997
45845
|
}
|
|
45998
45846
|
|
|
45999
45847
|
// src/commands/sessions/daemon/handleConnection.ts
|
|
46000
|
-
import { createInterface as
|
|
45848
|
+
import { createInterface as createInterface10 } from "readline";
|
|
46001
45849
|
|
|
46002
45850
|
// src/commands/sessions/daemon/handleHelloRequest.ts
|
|
46003
45851
|
var handleHelloRequest = (client, m, d) => {
|
|
@@ -46012,10 +45860,10 @@ var handleHelloRequest = (client, m, d) => {
|
|
|
46012
45860
|
};
|
|
46013
45861
|
|
|
46014
45862
|
// src/commands/sessions/daemon/creator.ts
|
|
46015
|
-
function creator(isNew,
|
|
45863
|
+
function creator(isNew, spawn10) {
|
|
46016
45864
|
return (client, m, d) => {
|
|
46017
45865
|
if (m.links.route(client, d)) return;
|
|
46018
|
-
const result =
|
|
45866
|
+
const result = spawn10(m, d);
|
|
46019
45867
|
if (typeof result !== "string") {
|
|
46020
45868
|
sendTo(client, { type: "error", message: result.error });
|
|
46021
45869
|
return;
|
|
@@ -46583,7 +46431,7 @@ function handleConnection(socket, manager) {
|
|
|
46583
46431
|
};
|
|
46584
46432
|
manager.addClient(client);
|
|
46585
46433
|
manager.clients.greet(client);
|
|
46586
|
-
const lines2 =
|
|
46434
|
+
const lines2 = createInterface10({ input: socket });
|
|
46587
46435
|
lines2.on("error", () => {
|
|
46588
46436
|
});
|
|
46589
46437
|
lines2.on("line", (line) => {
|
|
@@ -46782,37 +46630,6 @@ function failed2(hop, error, remediation) {
|
|
|
46782
46630
|
return { hop, ok: false, error, remediation };
|
|
46783
46631
|
}
|
|
46784
46632
|
|
|
46785
|
-
// src/commands/sessions/nodes/agentHop.ts
|
|
46786
|
-
var ONEPASSWORD_AGENT = '"~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"';
|
|
46787
|
-
async function agentHop(ssh, probes) {
|
|
46788
|
-
const agent = await probes.sshAgent(ssh.alias);
|
|
46789
|
-
switch (agent.status) {
|
|
46790
|
-
case "ok":
|
|
46791
|
-
return passed(
|
|
46792
|
-
"agent",
|
|
46793
|
-
`${agent.keys} key(s)${agent.socket ? ` via ${agent.socket}` : ""}`
|
|
46794
|
-
);
|
|
46795
|
-
case "missing":
|
|
46796
|
-
return failed2(
|
|
46797
|
-
"agent",
|
|
46798
|
-
`no IdentityAgent for ${ssh.alias} and SSH_AUTH_SOCK is unset`,
|
|
46799
|
-
`IdentityAgent missing \u2014 add \`IdentityAgent ${ONEPASSWORD_AGENT}\` under \`Host ${ssh.alias}\` in ~/.ssh/config`
|
|
46800
|
-
);
|
|
46801
|
-
case "no-keys":
|
|
46802
|
-
return failed2(
|
|
46803
|
-
"agent",
|
|
46804
|
-
`the agent${agent.socket ? ` at ${agent.socket}` : ""} holds no keys`,
|
|
46805
|
-
"add or import an SSH key in 1Password, then allow it in the SSH agent"
|
|
46806
|
-
);
|
|
46807
|
-
case "unreachable":
|
|
46808
|
-
return failed2(
|
|
46809
|
-
"agent",
|
|
46810
|
-
agent.error,
|
|
46811
|
-
"1Password SSH agent not reachable \u2014 open and unlock 1Password and turn on Settings \u2192 Developer \u2192 Use the SSH agent"
|
|
46812
|
-
);
|
|
46813
|
-
}
|
|
46814
|
-
}
|
|
46815
|
-
|
|
46816
46633
|
// src/commands/sessions/nodes/fetchPeerJson.ts
|
|
46817
46634
|
var PEER_TIMEOUT_MS = 3e3;
|
|
46818
46635
|
function peerErrorCode(error) {
|
|
@@ -46899,45 +46716,6 @@ function linkStateHop(spec, probes) {
|
|
|
46899
46716
|
);
|
|
46900
46717
|
}
|
|
46901
46718
|
|
|
46902
|
-
// src/commands/sessions/nodes/sshHop.ts
|
|
46903
|
-
var REMEDIATIONS = [
|
|
46904
|
-
[
|
|
46905
|
-
/connection refused/i,
|
|
46906
|
-
(alias) => `Remote Login is off on ${alias} \u2014 on a Mac turn on System Settings \u2192 General \u2192 Sharing \u2192 Remote Login; on Windows run \`Start-Service sshd\` (OpenSSH Server)`
|
|
46907
|
-
],
|
|
46908
|
-
[
|
|
46909
|
-
/could not resolve hostname/i,
|
|
46910
|
-
(alias) => `no \`Host ${alias}\` in ~/.ssh/config and ${alias} does not resolve \u2014 add a Host entry with its HostName`
|
|
46911
|
-
],
|
|
46912
|
-
[
|
|
46913
|
-
/host key verification failed/i,
|
|
46914
|
-
(alias) => `run \`ssh ${alias}\` once to accept its host key`
|
|
46915
|
-
],
|
|
46916
|
-
[
|
|
46917
|
-
/agent refused operation|sign_and_send_pubkey/i,
|
|
46918
|
-
() => "1Password refused to sign \u2014 unlock it and approve the key request"
|
|
46919
|
-
],
|
|
46920
|
-
[
|
|
46921
|
-
/permission denied/i,
|
|
46922
|
-
(alias) => `${alias} rejected every key offered \u2014 add this node's 1Password public key to ~/.ssh/authorized_keys on ${alias} (C:\\ProgramData\\ssh\\administrators_authorized_keys for a Windows administrator)`
|
|
46923
|
-
],
|
|
46924
|
-
[
|
|
46925
|
-
/timed out/i,
|
|
46926
|
-
(alias) => `${alias} did not answer on its ssh port \u2014 is it awake and on this network?`
|
|
46927
|
-
]
|
|
46928
|
-
];
|
|
46929
|
-
async function sshHop(ssh, probes) {
|
|
46930
|
-
const { code, stderr } = await probes.ssh(ssh.alias);
|
|
46931
|
-
if (code === 0) return passed("ssh", `ssh ${ssh.alias} authenticated`);
|
|
46932
|
-
const error = stderr || `ssh exited ${code}`;
|
|
46933
|
-
const match = REMEDIATIONS.find(([pattern2]) => pattern2.test(error));
|
|
46934
|
-
return failed2(
|
|
46935
|
-
"ssh",
|
|
46936
|
-
error,
|
|
46937
|
-
match?.[1](ssh.alias) ?? `run \`ssh -v ${ssh.alias}\` to see where it fails`
|
|
46938
|
-
);
|
|
46939
|
-
}
|
|
46940
|
-
|
|
46941
46719
|
// src/commands/sessions/nodes/findTailscalePeer.ts
|
|
46942
46720
|
function findTailscalePeer(status2, hostname2) {
|
|
46943
46721
|
const nodes = [
|
|
@@ -46988,18 +46766,6 @@ async function tailscaleHop(spec, probes) {
|
|
|
46988
46766
|
);
|
|
46989
46767
|
}
|
|
46990
46768
|
|
|
46991
|
-
// src/commands/sessions/nodes/tunnelHop.ts
|
|
46992
|
-
async function tunnelHop(spec, ssh, probes) {
|
|
46993
|
-
const bound = `127.0.0.1:${ssh.localPort}`;
|
|
46994
|
-
if (await probes.tunnel(ssh.localPort))
|
|
46995
|
-
return passed("tunnel", `${bound} \u2192 ${ssh.alias}:${ssh.port}`);
|
|
46996
|
-
return failed2(
|
|
46997
|
-
"tunnel",
|
|
46998
|
-
`nothing bound on ${bound}`,
|
|
46999
|
-
`this node's daemon keeps \`ssh -N -L ${ssh.localPort}:127.0.0.1:${ssh.port} ${ssh.alias}\` up \u2014 run \`assist daemon restart\` and check daemon.log for \`link ${spec.name} tunnel:\` and \`link ${spec.name} ssh:\` lines`
|
|
47000
|
-
);
|
|
47001
|
-
}
|
|
47002
|
-
|
|
47003
46769
|
// src/commands/sessions/nodes/tailscaleServeRemediation.ts
|
|
47004
46770
|
function tailscaleServeRemediation(spec, error) {
|
|
47005
46771
|
const status2 = error.status;
|
|
@@ -47016,8 +46782,6 @@ function isTailscaleLink(spec) {
|
|
|
47016
46782
|
|
|
47017
46783
|
// src/commands/sessions/nodes/webHop.ts
|
|
47018
46784
|
function webRemediation(spec, error) {
|
|
47019
|
-
if (spec.ssh && error.status === void 0)
|
|
47020
|
-
return `nothing listening on ${spec.ssh.port} on ${spec.ssh.alias} \u2014 is project-switch running ${spec.name}'s web server?`;
|
|
47021
46785
|
const serve = isTailscaleLink(spec) ? tailscaleServeRemediation(spec, error) : void 0;
|
|
47022
46786
|
if (serve) return serve;
|
|
47023
46787
|
const { hostname: hostname2, port } = new URL(spec.url);
|
|
@@ -47047,7 +46811,7 @@ async function webHop(spec, probes) {
|
|
|
47047
46811
|
hop: failed2(
|
|
47048
46812
|
"web",
|
|
47049
46813
|
`peer reports nodeName ${health2.nodeName}, link expects ${spec.name}`,
|
|
47050
|
-
`relink with \`assist sessions nodes unlink ${spec.name}\` then \`assist sessions nodes link ${health2.nodeName} ${spec.
|
|
46814
|
+
`relink with \`assist sessions nodes unlink ${spec.name}\` then \`assist sessions nodes link ${health2.nodeName} ${spec.url}\`, or set sessions.nodeName on the peer`
|
|
47051
46815
|
)
|
|
47052
46816
|
};
|
|
47053
46817
|
return {
|
|
@@ -47073,17 +46837,6 @@ function peerDaemonHop(spec, health2) {
|
|
|
47073
46837
|
async function diagnoseLink(spec, probes) {
|
|
47074
46838
|
const hops = [];
|
|
47075
46839
|
const done2 = () => ({ ...spec, ok: hops.every((h) => h.ok), hops });
|
|
47076
|
-
if (spec.ssh) {
|
|
47077
|
-
const { ssh } = spec;
|
|
47078
|
-
for (const probe of [
|
|
47079
|
-
() => agentHop(ssh, probes),
|
|
47080
|
-
() => sshHop(ssh, probes),
|
|
47081
|
-
() => tunnelHop(spec, ssh, probes)
|
|
47082
|
-
]) {
|
|
47083
|
-
hops.push(await probe());
|
|
47084
|
-
if (!hops.at(-1)?.ok) return done2();
|
|
47085
|
-
}
|
|
47086
|
-
}
|
|
47087
46840
|
if (isTailscaleLink(spec)) {
|
|
47088
46841
|
hops.push(await tailscaleHop(spec, probes));
|
|
47089
46842
|
if (!hops.at(-1)?.ok) return done2();
|
|
@@ -47146,77 +46899,6 @@ async function probePeerHello(url) {
|
|
|
47146
46899
|
return result;
|
|
47147
46900
|
}
|
|
47148
46901
|
|
|
47149
|
-
// src/commands/sessions/nodes/probeSsh.ts
|
|
47150
|
-
import { spawn as spawn11 } from "child_process";
|
|
47151
|
-
var PROBE_TIMEOUT_MS = 15e3;
|
|
47152
|
-
function probeSsh(alias) {
|
|
47153
|
-
return new Promise((resolve26) => {
|
|
47154
|
-
const child = spawn11(
|
|
47155
|
-
"ssh",
|
|
47156
|
-
["-o", "BatchMode=yes", "-o", "ConnectTimeout=5", alias, "exit"],
|
|
47157
|
-
{ stdio: ["ignore", "ignore", "pipe"], windowsHide: true }
|
|
47158
|
-
);
|
|
47159
|
-
let stderr = "";
|
|
47160
|
-
child.stderr.on("data", (chunk) => {
|
|
47161
|
-
stderr += chunk;
|
|
47162
|
-
});
|
|
47163
|
-
const timer = setTimeout(() => child.kill(), PROBE_TIMEOUT_MS);
|
|
47164
|
-
child.once("error", (error) => {
|
|
47165
|
-
clearTimeout(timer);
|
|
47166
|
-
resolve26({ code: null, stderr: error.message });
|
|
47167
|
-
});
|
|
47168
|
-
child.once("close", (code) => {
|
|
47169
|
-
clearTimeout(timer);
|
|
47170
|
-
resolve26({ code, stderr: stderr.trim() });
|
|
47171
|
-
});
|
|
47172
|
-
});
|
|
47173
|
-
}
|
|
47174
|
-
|
|
47175
|
-
// src/commands/sessions/nodes/probeSshAgent.ts
|
|
47176
|
-
import { spawnSync as spawnSync9 } from "child_process";
|
|
47177
|
-
import { homedir as homedir25 } from "os";
|
|
47178
|
-
var PROBE_TIMEOUT_MS2 = 5e3;
|
|
47179
|
-
function parseIdentityAgent(sshConfig, env = process.env) {
|
|
47180
|
-
const line = sshConfig.split(/\r?\n/).find((l) => l.toLowerCase().startsWith("identityagent "));
|
|
47181
|
-
const value = line?.slice("identityagent ".length).trim().replace(/^"(.*)"$/, "$1");
|
|
47182
|
-
if (!value || value.toLowerCase() === "none") return void 0;
|
|
47183
|
-
if (value === "SSH_AUTH_SOCK" || value === "$SSH_AUTH_SOCK")
|
|
47184
|
-
return env.SSH_AUTH_SOCK;
|
|
47185
|
-
return value.replace(/^~(?=$|[/\\])/, homedir25());
|
|
47186
|
-
}
|
|
47187
|
-
function configuredAgent(alias) {
|
|
47188
|
-
const result = spawnSync9("ssh", ["-G", alias], {
|
|
47189
|
-
encoding: "utf8",
|
|
47190
|
-
timeout: PROBE_TIMEOUT_MS2,
|
|
47191
|
-
windowsHide: true
|
|
47192
|
-
});
|
|
47193
|
-
return parseIdentityAgent(result.stdout ?? "") ?? process.env.SSH_AUTH_SOCK;
|
|
47194
|
-
}
|
|
47195
|
-
async function probeSshAgent(alias) {
|
|
47196
|
-
const socket = configuredAgent(alias);
|
|
47197
|
-
if (!socket && process.platform !== "win32") return { status: "missing" };
|
|
47198
|
-
const result = spawnSync9("ssh-add", ["-l"], {
|
|
47199
|
-
encoding: "utf8",
|
|
47200
|
-
timeout: PROBE_TIMEOUT_MS2,
|
|
47201
|
-
windowsHide: true,
|
|
47202
|
-
env: socket ? { ...process.env, SSH_AUTH_SOCK: socket } : process.env
|
|
47203
|
-
});
|
|
47204
|
-
if (result.error)
|
|
47205
|
-
return { status: "unreachable", socket, error: result.error.message };
|
|
47206
|
-
if (result.status === 0)
|
|
47207
|
-
return {
|
|
47208
|
-
status: "ok",
|
|
47209
|
-
socket,
|
|
47210
|
-
keys: result.stdout.trim().split(/\r?\n/).length
|
|
47211
|
-
};
|
|
47212
|
-
if (result.status === 1) return { status: "no-keys", socket };
|
|
47213
|
-
return {
|
|
47214
|
-
status: "unreachable",
|
|
47215
|
-
socket,
|
|
47216
|
-
error: result.stderr.trim() || `ssh-add exited ${result.status}`
|
|
47217
|
-
};
|
|
47218
|
-
}
|
|
47219
|
-
|
|
47220
46902
|
// src/commands/sessions/nodes/printReport.ts
|
|
47221
46903
|
import chalk254 from "chalk";
|
|
47222
46904
|
function printReport(report2) {
|
|
@@ -47245,9 +46927,6 @@ function doctorProbes(live) {
|
|
|
47245
46927
|
return {
|
|
47246
46928
|
health: (url) => fetchPeerJson(url, "/api/health"),
|
|
47247
46929
|
hello: probePeerHello,
|
|
47248
|
-
sshAgent: probeSshAgent,
|
|
47249
|
-
ssh: probeSsh,
|
|
47250
|
-
tunnel: (localPort) => portAccepts(localPort),
|
|
47251
46930
|
tailscale: tailscaleStatus,
|
|
47252
46931
|
linkState: (name) => {
|
|
47253
46932
|
if (!live) return "no-daemon";
|
|
@@ -47329,7 +47008,7 @@ async function nodeLogs(name, options2) {
|
|
|
47329
47008
|
}
|
|
47330
47009
|
|
|
47331
47010
|
// src/commands/sessions/nodes/linkNode.ts
|
|
47332
|
-
import
|
|
47011
|
+
import chalk258 from "chalk";
|
|
47333
47012
|
|
|
47334
47013
|
// src/commands/sessions/nodes/notifyDaemonLinks.ts
|
|
47335
47014
|
import chalk256 from "chalk";
|
|
@@ -47355,11 +47034,10 @@ async function notifyDaemonLinks() {
|
|
|
47355
47034
|
}
|
|
47356
47035
|
}
|
|
47357
47036
|
|
|
47037
|
+
// src/commands/sessions/nodes/readLinks.ts
|
|
47038
|
+
import chalk257 from "chalk";
|
|
47039
|
+
|
|
47358
47040
|
// src/commands/sessions/nodes/writeLinks.ts
|
|
47359
|
-
function readLinks() {
|
|
47360
|
-
const sessions = loadGlobalConfigRaw().sessions;
|
|
47361
|
-
return sessions?.links ?? [];
|
|
47362
|
-
}
|
|
47363
47041
|
async function writeLinks(links2) {
|
|
47364
47042
|
const config = loadGlobalConfigRaw();
|
|
47365
47043
|
const sessions = { ...config.sessions };
|
|
@@ -47371,6 +47049,20 @@ async function writeLinks(links2) {
|
|
|
47371
47049
|
saveGlobalConfig(updated2);
|
|
47372
47050
|
}
|
|
47373
47051
|
|
|
47052
|
+
// src/commands/sessions/nodes/readLinks.ts
|
|
47053
|
+
async function readLinks() {
|
|
47054
|
+
const sessions = loadGlobalConfigRaw().sessions;
|
|
47055
|
+
const stored = sessions?.links ?? [];
|
|
47056
|
+
const links2 = stored.filter((link3) => !!link3.url);
|
|
47057
|
+
if (links2.length === stored.length) return links2;
|
|
47058
|
+
await writeLinks(links2);
|
|
47059
|
+
const dropped = stored.filter((link3) => !link3.url).map((link3) => link3.name);
|
|
47060
|
+
console.log(
|
|
47061
|
+
chalk257.yellow(`Removed ${dropped.join(", ")}: ${SSH_LINK_RETIRED}`)
|
|
47062
|
+
);
|
|
47063
|
+
return links2;
|
|
47064
|
+
}
|
|
47065
|
+
|
|
47374
47066
|
// src/commands/sessions/nodes/tailscaleLinkUrl.ts
|
|
47375
47067
|
async function localTailnetSuffix() {
|
|
47376
47068
|
return tailnetSuffix(await tailscaleStatus());
|
|
@@ -47399,82 +47091,54 @@ function parseLinkUrl(url) {
|
|
|
47399
47091
|
}
|
|
47400
47092
|
|
|
47401
47093
|
// src/commands/sessions/nodes/buildLink.ts
|
|
47402
|
-
async function buildLink(name, url, options2,
|
|
47403
|
-
if (
|
|
47404
|
-
throw new Error(
|
|
47405
|
-
"pass only one of <url>, --tailscale <host> or --ssh <alias>"
|
|
47406
|
-
);
|
|
47094
|
+
async function buildLink(name, url, options2, resolveTailnetSuffix) {
|
|
47095
|
+
if (url && options2.tailscale)
|
|
47096
|
+
throw new Error("pass only one of <url> or --tailscale <host>");
|
|
47407
47097
|
if (url) return { name, url: parseLinkUrl(url) };
|
|
47408
|
-
if (options2.tailscale)
|
|
47409
|
-
const port2 = parsePort("--port", options2.port);
|
|
47410
|
-
return {
|
|
47411
|
-
name,
|
|
47412
|
-
url: await tailscaleLinkUrl(
|
|
47413
|
-
options2.tailscale,
|
|
47414
|
-
port2,
|
|
47415
|
-
resolveTailnetSuffix
|
|
47416
|
-
)
|
|
47417
|
-
};
|
|
47418
|
-
}
|
|
47419
|
-
if (!options2.ssh)
|
|
47098
|
+
if (!options2.tailscale)
|
|
47420
47099
|
throw new Error(
|
|
47421
|
-
"pass the peer's <url
|
|
47100
|
+
"pass the peer's <url> or --tailscale <host> --port <port>"
|
|
47422
47101
|
);
|
|
47423
47102
|
const port = parsePort("--port", options2.port);
|
|
47424
|
-
|
|
47425
|
-
|
|
47426
|
-
|
|
47427
|
-
|
|
47428
|
-
const taken = new Set(others.map((link3) => toLinkSpec(link3).ssh?.localPort));
|
|
47429
|
-
let candidate = defaultTunnelPort(port);
|
|
47430
|
-
while (taken.has(candidate)) candidate++;
|
|
47431
|
-
return candidate;
|
|
47103
|
+
return {
|
|
47104
|
+
name,
|
|
47105
|
+
url: await tailscaleLinkUrl(options2.tailscale, port, resolveTailnetSuffix)
|
|
47106
|
+
};
|
|
47432
47107
|
}
|
|
47433
47108
|
|
|
47434
47109
|
// src/commands/sessions/nodes/linkNode.ts
|
|
47435
47110
|
async function linkNode(name, url, options2) {
|
|
47436
47111
|
if (name.includes(":")) throw new Error("node names cannot contain ':'");
|
|
47112
|
+
const others = (await readLinks()).filter((link4) => link4.name !== name);
|
|
47437
47113
|
if (name === resolveNodeName())
|
|
47438
47114
|
throw new Error(`${name} is this node; link to a different node`);
|
|
47439
|
-
const
|
|
47440
|
-
const link3 = await buildLink(name, url, options2, others);
|
|
47115
|
+
const link3 = await buildLink(name, url, options2);
|
|
47441
47116
|
await writeLinks([...others, link3]);
|
|
47442
|
-
console.log(
|
|
47443
|
-
chalk257.green(`Linked ${name} (${describeTarget(toLinkSpec(link3))})`)
|
|
47444
|
-
);
|
|
47117
|
+
console.log(chalk258.green(`Linked ${name} (${link3.url})`));
|
|
47445
47118
|
await notifyDaemonLinks();
|
|
47446
47119
|
}
|
|
47447
47120
|
|
|
47448
47121
|
// src/commands/sessions/nodes/registerLinkCommand.ts
|
|
47449
47122
|
function registerLinkCommand(nodes) {
|
|
47450
47123
|
nodes.command("link <name> [url]").description(
|
|
47451
|
-
"Link a peer node by its web server URL
|
|
47124
|
+
"Link a peer node by its web server URL or by its Tailscale name with --tailscale and --port (name must match the peer's sessions.nodeName)"
|
|
47452
47125
|
).option(
|
|
47453
47126
|
"--tailscale <host>",
|
|
47454
47127
|
"Dial the peer at https://<host>.<tailnet>.ts.net:<port> (the peer runs tailscale serve for its web server port)"
|
|
47455
|
-
).option(
|
|
47456
|
-
"--ssh <alias>",
|
|
47457
|
-
"Tunnel to the peer through this ~/.ssh/config alias"
|
|
47458
|
-
).option(
|
|
47459
|
-
"--port <port>",
|
|
47460
|
-
"The peer's web server port (with --tailscale or --ssh)"
|
|
47461
|
-
).option(
|
|
47462
|
-
"--local-port <port>",
|
|
47463
|
-
"Local end of the ssh tunnel (default: 43000 + port % 1000, bumped past other links)"
|
|
47464
|
-
).action(linkNode);
|
|
47128
|
+
).option("--port <port>", "The peer's web server port (with --tailscale)").action(linkNode);
|
|
47465
47129
|
}
|
|
47466
47130
|
|
|
47467
47131
|
// src/commands/sessions/nodes/unlinkNode.ts
|
|
47468
|
-
import
|
|
47132
|
+
import chalk259 from "chalk";
|
|
47469
47133
|
async function unlinkNode(name) {
|
|
47470
|
-
const links2 = readLinks();
|
|
47134
|
+
const links2 = await readLinks();
|
|
47471
47135
|
const remaining = links2.filter((link3) => link3.name !== name);
|
|
47472
47136
|
if (remaining.length === links2.length) {
|
|
47473
|
-
console.log(
|
|
47137
|
+
console.log(chalk259.yellow(`No link named ${name}`));
|
|
47474
47138
|
return;
|
|
47475
47139
|
}
|
|
47476
47140
|
await writeLinks(remaining);
|
|
47477
|
-
console.log(
|
|
47141
|
+
console.log(chalk259.green(`Unlinked ${name}`));
|
|
47478
47142
|
await notifyDaemonLinks();
|
|
47479
47143
|
}
|
|
47480
47144
|
|
|
@@ -47495,14 +47159,14 @@ function registerNodes(sessions) {
|
|
|
47495
47159
|
}
|
|
47496
47160
|
|
|
47497
47161
|
// src/commands/sessions/daemon/requestSessionOutput.ts
|
|
47498
|
-
import { createInterface as
|
|
47162
|
+
import { createInterface as createInterface11 } from "readline";
|
|
47499
47163
|
var OUTPUT_TIMEOUT_MS = 5e3;
|
|
47500
47164
|
async function requestSessionOutput(target) {
|
|
47501
47165
|
const socket = await connectToDaemon().catch(() => {
|
|
47502
47166
|
throw new Error("No sessions daemon is running");
|
|
47503
47167
|
});
|
|
47504
47168
|
try {
|
|
47505
|
-
const lines2 =
|
|
47169
|
+
const lines2 = createInterface11({ input: socket });
|
|
47506
47170
|
lines2.on("error", () => {
|
|
47507
47171
|
});
|
|
47508
47172
|
const reply2 = readDaemonMessage(
|
|
@@ -47605,7 +47269,7 @@ async function renameSession(title) {
|
|
|
47605
47269
|
|
|
47606
47270
|
// src/commands/sessions/summarise.ts
|
|
47607
47271
|
import * as fs58 from "fs";
|
|
47608
|
-
import
|
|
47272
|
+
import chalk260 from "chalk";
|
|
47609
47273
|
|
|
47610
47274
|
// src/commands/sessions/summarise/shared.ts
|
|
47611
47275
|
import * as fs57 from "fs";
|
|
@@ -47664,22 +47328,22 @@ ${firstMessage}`);
|
|
|
47664
47328
|
async function summarise2(options2) {
|
|
47665
47329
|
const files = await discoverSessionFiles();
|
|
47666
47330
|
if (files.length === 0) {
|
|
47667
|
-
console.log(
|
|
47331
|
+
console.log(chalk260.yellow("No sessions found."));
|
|
47668
47332
|
return;
|
|
47669
47333
|
}
|
|
47670
47334
|
const toProcess = selectCandidates(files, options2);
|
|
47671
47335
|
if (toProcess.length === 0) {
|
|
47672
|
-
console.log(
|
|
47336
|
+
console.log(chalk260.green("All sessions already summarised."));
|
|
47673
47337
|
return;
|
|
47674
47338
|
}
|
|
47675
47339
|
console.log(
|
|
47676
|
-
|
|
47340
|
+
chalk260.cyan(
|
|
47677
47341
|
`Summarising ${toProcess.length} session(s) (${files.length} total)\u2026`
|
|
47678
47342
|
)
|
|
47679
47343
|
);
|
|
47680
47344
|
const { succeeded, failed: failed3 } = processSessions(toProcess);
|
|
47681
47345
|
console.log(
|
|
47682
|
-
|
|
47346
|
+
chalk260.green(`Done: ${succeeded} summarised`) + (failed3 > 0 ? chalk260.yellow(`, ${failed3} skipped`) : "")
|
|
47683
47347
|
);
|
|
47684
47348
|
}
|
|
47685
47349
|
function selectCandidates(files, options2) {
|
|
@@ -47699,16 +47363,16 @@ function processSessions(files) {
|
|
|
47699
47363
|
let failed3 = 0;
|
|
47700
47364
|
for (let i = 0; i < files.length; i++) {
|
|
47701
47365
|
const file = files[i];
|
|
47702
|
-
process.stdout.write(
|
|
47366
|
+
process.stdout.write(chalk260.dim(` [${i + 1}/${files.length}] `));
|
|
47703
47367
|
const summary = summariseSession(file);
|
|
47704
47368
|
if (summary) {
|
|
47705
47369
|
writeSummary(file, summary);
|
|
47706
47370
|
succeeded++;
|
|
47707
|
-
process.stdout.write(`${
|
|
47371
|
+
process.stdout.write(`${chalk260.green("\u2713")} ${summary}
|
|
47708
47372
|
`);
|
|
47709
47373
|
} else {
|
|
47710
47374
|
failed3++;
|
|
47711
|
-
process.stdout.write(` ${
|
|
47375
|
+
process.stdout.write(` ${chalk260.yellow("skip")}
|
|
47712
47376
|
`);
|
|
47713
47377
|
}
|
|
47714
47378
|
}
|
|
@@ -47738,10 +47402,10 @@ function registerSessions(program2) {
|
|
|
47738
47402
|
}
|
|
47739
47403
|
|
|
47740
47404
|
// src/reportCliError.ts
|
|
47741
|
-
import
|
|
47405
|
+
import chalk261 from "chalk";
|
|
47742
47406
|
function reportCliError(error) {
|
|
47743
47407
|
if (error instanceof InvalidItemIdError || error instanceof AmbiguousRepoConfigError || error instanceof UnknownRepoConfigError || error instanceof MissingRunCwdError || error instanceof MiroExtractError) {
|
|
47744
|
-
console.error(
|
|
47408
|
+
console.error(chalk261.red(error.message));
|
|
47745
47409
|
} else {
|
|
47746
47410
|
console.error(error);
|
|
47747
47411
|
}
|