@staff0rd/assist 0.756.0 → 0.757.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -30
- package/claude/skills/review-ci/scripts/review.mjs +111 -111
- package/dist/commands/sessions/web/bundle.js +360 -360
- package/dist/index.js +409 -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.1",
|
|
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);
|
|
@@ -15040,6 +15033,20 @@ import {
|
|
|
15040
15033
|
} from "http";
|
|
15041
15034
|
import { request as httpsRequest } from "https";
|
|
15042
15035
|
|
|
15036
|
+
// src/commands/sessions/web/peerTimeoutMs.ts
|
|
15037
|
+
var peerTimeoutMs = 2e4;
|
|
15038
|
+
|
|
15039
|
+
// src/commands/sessions/web/boundUpstream.ts
|
|
15040
|
+
function boundUpstream(upstream, res) {
|
|
15041
|
+
upstream.setTimeout(
|
|
15042
|
+
peerTimeoutMs,
|
|
15043
|
+
() => upstream.destroy(new Error(`no response after ${peerTimeoutMs}ms`))
|
|
15044
|
+
);
|
|
15045
|
+
res.on("close", () => {
|
|
15046
|
+
if (!res.writableFinished) upstream.destroy();
|
|
15047
|
+
});
|
|
15048
|
+
}
|
|
15049
|
+
|
|
15043
15050
|
// src/commands/sessions/web/isQuietPoll.ts
|
|
15044
15051
|
var POLLED_PATHS = /* @__PURE__ */ new Set(["/api/git-status"]);
|
|
15045
15052
|
function isQuietPoll(pathname, status2) {
|
|
@@ -15078,6 +15085,7 @@ function forwardToPeer(req, res, node, url) {
|
|
|
15078
15085
|
},
|
|
15079
15086
|
(peer) => relayPeerResponse(peer, res, url.pathname, log2, resolve26)
|
|
15080
15087
|
);
|
|
15088
|
+
boundUpstream(upstream, res);
|
|
15081
15089
|
upstream.on("error", (error) => {
|
|
15082
15090
|
log2(`failed: ${error.message}`);
|
|
15083
15091
|
if (res.headersSent) res.destroy();
|
|
@@ -25275,36 +25283,36 @@ function stringOrUndefined(value) {
|
|
|
25275
25283
|
}
|
|
25276
25284
|
|
|
25277
25285
|
// 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:
|
|
25286
|
+
import { z as z9 } from "zod";
|
|
25287
|
+
var persistedSessionSchema = z9.object({
|
|
25288
|
+
id: z9.string().optional(),
|
|
25289
|
+
name: z9.string(),
|
|
25290
|
+
title: z9.string().optional(),
|
|
25291
|
+
generatedTitle: z9.string().optional(),
|
|
25292
|
+
subtitle: z9.string().optional(),
|
|
25293
|
+
commandType: z9.enum(["claude", "run", "assist"]),
|
|
25294
|
+
harness: z9.enum(["claude", "codex", "pi"]).optional(),
|
|
25295
|
+
status: z9.enum(["running", "waiting", "done", "error", "stopped"]).optional(),
|
|
25296
|
+
cwd: z9.string(),
|
|
25297
|
+
startedAt: z9.number(),
|
|
25298
|
+
runningMs: z9.number().optional(),
|
|
25299
|
+
claudeSessionId: z9.string().optional(),
|
|
25300
|
+
harnessSessionId: z9.string().optional(),
|
|
25301
|
+
initialPrompt: z9.string().optional(),
|
|
25302
|
+
runName: z9.string().optional(),
|
|
25303
|
+
runArgs: z9.array(z9.string()).optional(),
|
|
25304
|
+
assistArgs: z9.array(z9.string()).optional(),
|
|
25297
25305
|
activity: activitySchema.optional(),
|
|
25298
|
-
starred:
|
|
25299
|
-
watcher:
|
|
25300
|
-
design:
|
|
25301
|
-
auto:
|
|
25302
|
-
autoRun:
|
|
25303
|
-
autoAdvance:
|
|
25304
|
-
reviewStarted:
|
|
25305
|
-
launchedFrom:
|
|
25306
|
-
interrupted:
|
|
25307
|
-
undurable:
|
|
25306
|
+
starred: z9.boolean().optional(),
|
|
25307
|
+
watcher: z9.boolean().optional(),
|
|
25308
|
+
design: z9.boolean().optional(),
|
|
25309
|
+
auto: z9.boolean().optional(),
|
|
25310
|
+
autoRun: z9.boolean().optional(),
|
|
25311
|
+
autoAdvance: z9.boolean().optional(),
|
|
25312
|
+
reviewStarted: z9.boolean().optional(),
|
|
25313
|
+
launchedFrom: z9.string().optional(),
|
|
25314
|
+
interrupted: z9.object({ reason: z9.string(), at: z9.number() }).optional(),
|
|
25315
|
+
undurable: z9.object({ reason: z9.string(), removesTree: z9.boolean().optional() }).optional()
|
|
25308
25316
|
});
|
|
25309
25317
|
|
|
25310
25318
|
// src/commands/sessions/daemon/toPersistedSession.ts
|
|
@@ -38177,16 +38185,16 @@ function selectPassages(sources, selection) {
|
|
|
38177
38185
|
}
|
|
38178
38186
|
|
|
38179
38187
|
// src/commands/transcript/selectionSchema.ts
|
|
38180
|
-
import { z as
|
|
38181
|
-
var selectionSchema =
|
|
38182
|
-
keep:
|
|
38183
|
-
|
|
38184
|
-
file:
|
|
38185
|
-
from:
|
|
38186
|
-
to:
|
|
38188
|
+
import { z as z10 } from "zod";
|
|
38189
|
+
var selectionSchema = z10.strictObject({
|
|
38190
|
+
keep: z10.array(
|
|
38191
|
+
z10.strictObject({
|
|
38192
|
+
file: z10.string().trim().min(1, "file is required"),
|
|
38193
|
+
from: z10.string().trim().min(1, "from is required"),
|
|
38194
|
+
to: z10.string().trim().min(1, "to is required")
|
|
38187
38195
|
})
|
|
38188
38196
|
).min(1, "a selection needs at least one keep range"),
|
|
38189
|
-
removed:
|
|
38197
|
+
removed: z10.array(z10.string().trim().min(1)).default([])
|
|
38190
38198
|
});
|
|
38191
38199
|
|
|
38192
38200
|
// src/commands/transcript/widenAudienceInText.ts
|
|
@@ -40228,14 +40236,6 @@ function registerRun(program2) {
|
|
|
40228
40236
|
|
|
40229
40237
|
// src/commands/sessions/nodes/formatLink.ts
|
|
40230
40238
|
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
40239
|
var STATE_COLOURS = {
|
|
40240
40240
|
connected: chalk253.green,
|
|
40241
40241
|
connecting: chalk253.yellow,
|
|
@@ -40247,7 +40247,7 @@ function formatLink(link3) {
|
|
|
40247
40247
|
const peer = link3.peerVersion ? ` peer ${link3.peerVersion}` : "";
|
|
40248
40248
|
const error = link3.error ? `
|
|
40249
40249
|
${chalk253.dim(`last error${link3.errorAt ? ` ${link3.errorAt}` : ""}: ${link3.error}`)}` : "";
|
|
40250
|
-
return ` ${link3.name} ${colour(link3.state)} ${
|
|
40250
|
+
return ` ${link3.name} ${colour(link3.state)} ${link3.url}${peer}${error}`;
|
|
40251
40251
|
}
|
|
40252
40252
|
|
|
40253
40253
|
// src/commands/sessions/daemon/listDaemonPids.ts
|
|
@@ -40479,9 +40479,9 @@ function createAutoExit(exit, graceMs = DEFAULT_GRACE_MS) {
|
|
|
40479
40479
|
}
|
|
40480
40480
|
|
|
40481
40481
|
// src/commands/sessions/daemon/loadActiveSelection.ts
|
|
40482
|
-
import { z as
|
|
40482
|
+
import { z as z11 } from "zod";
|
|
40483
40483
|
var ACTIVE_FILE = "active.json";
|
|
40484
|
-
var activeSelectionSchema =
|
|
40484
|
+
var activeSelectionSchema = z11.record(z11.string(), z11.string());
|
|
40485
40485
|
function loadActiveSelection() {
|
|
40486
40486
|
const parsed = activeSelectionSchema.safeParse(
|
|
40487
40487
|
loadJson(ACTIVE_FILE)
|
|
@@ -44144,10 +44144,10 @@ function restoreAllSessions(spawner, sessions, notify2) {
|
|
|
44144
44144
|
|
|
44145
44145
|
// src/commands/sessions/daemon/retrySession.ts
|
|
44146
44146
|
function retrySession(session, clients, onStatusChange) {
|
|
44147
|
-
const
|
|
44148
|
-
if (!
|
|
44147
|
+
const spawn10 = respawnThunk(session);
|
|
44148
|
+
if (!spawn10) return false;
|
|
44149
44149
|
const respawn = () => {
|
|
44150
|
-
respawnSession(session,
|
|
44150
|
+
respawnSession(session, spawn10, "running", clients, onStatusChange);
|
|
44151
44151
|
daemonLog(`session ${session.id} retried: ${session.name}`);
|
|
44152
44152
|
};
|
|
44153
44153
|
const pty2 = session.pty;
|
|
@@ -44721,134 +44721,6 @@ async function selfUpdatePeer(url) {
|
|
|
44721
44721
|
throw new Error(body.error ?? `self-update responded ${response.status}`);
|
|
44722
44722
|
}
|
|
44723
44723
|
|
|
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
44724
|
// src/commands/sessions/daemon/links/linkDeps.ts
|
|
44853
44725
|
function linkDeps(options2, callbacks) {
|
|
44854
44726
|
return {
|
|
@@ -44866,7 +44738,6 @@ function linkDeps(options2, callbacks) {
|
|
|
44866
44738
|
callbacks.onHistoryChanged
|
|
44867
44739
|
),
|
|
44868
44740
|
transport: options2.transport ?? connectLinkWebSocket,
|
|
44869
|
-
tunnel: options2.tunnel ?? sshTunnelFor,
|
|
44870
44741
|
heal: options2.heal ?? selfUpdatePeer,
|
|
44871
44742
|
reconnectMs: options2.reconnectMs ?? 3e3,
|
|
44872
44743
|
blockedRetryMs: options2.blockedRetryMs ?? 6e4,
|
|
@@ -44973,7 +44844,6 @@ function createLinkContext(spec, deps2) {
|
|
|
44973
44844
|
deps: deps2,
|
|
44974
44845
|
relay: createRelayState(spec.name, deps2),
|
|
44975
44846
|
breaker: new LaunchCircuitBreaker(`link ${spec.name} ws`),
|
|
44976
|
-
tunnel: deps2.tunnel(spec),
|
|
44977
44847
|
socket: null,
|
|
44978
44848
|
greeted: false,
|
|
44979
44849
|
state: "disconnected",
|
|
@@ -44992,7 +44862,6 @@ function describeLink(ctx) {
|
|
|
44992
44862
|
return {
|
|
44993
44863
|
name: ctx.spec.name,
|
|
44994
44864
|
url: ctx.spec.url,
|
|
44995
|
-
ssh: ctx.spec.ssh,
|
|
44996
44865
|
state: ctx.state,
|
|
44997
44866
|
error: ctx.blockedMessage ?? ctx.lastError?.message,
|
|
44998
44867
|
errorAt: ctx.lastError?.at,
|
|
@@ -45092,16 +44961,16 @@ function linkHealRefusal(node, peerVersion, healAttempted) {
|
|
|
45092
44961
|
}
|
|
45093
44962
|
|
|
45094
44963
|
// src/commands/sessions/daemon/links/scheduleReconnect.ts
|
|
45095
|
-
function armReconnect(ctx,
|
|
44964
|
+
function armReconnect(ctx, delay2) {
|
|
45096
44965
|
clearTimeout(ctx.reconnectTimer);
|
|
45097
|
-
ctx.reconnectTimer = setTimeout(ctx.connect,
|
|
44966
|
+
ctx.reconnectTimer = setTimeout(ctx.connect, delay2);
|
|
45098
44967
|
ctx.reconnectTimer.unref?.();
|
|
45099
44968
|
}
|
|
45100
44969
|
function scheduleReconnect2(ctx) {
|
|
45101
44970
|
if (ctx.disposed) return;
|
|
45102
44971
|
if (ctx.blockedMessage) return armReconnect(ctx, ctx.deps.blockedRetryMs);
|
|
45103
|
-
const
|
|
45104
|
-
armReconnect(ctx,
|
|
44972
|
+
const delay2 = ctx.breaker.tripped() ? ctx.breaker.remainingMs() : ctx.deps.reconnectMs;
|
|
44973
|
+
armReconnect(ctx, delay2);
|
|
45105
44974
|
}
|
|
45106
44975
|
function reconnectNow(ctx) {
|
|
45107
44976
|
ctx.breaker.clear();
|
|
@@ -45365,8 +45234,6 @@ async function openLink(ctx) {
|
|
|
45365
45234
|
if (ctx.breaker.tripped()) return scheduleReconnect2(ctx);
|
|
45366
45235
|
if (!ctx.blockedMessage) setLinkState(ctx, "connecting");
|
|
45367
45236
|
try {
|
|
45368
|
-
await ctx.tunnel?.ready();
|
|
45369
|
-
if (ctx.disposed) return;
|
|
45370
45237
|
daemonLog(`link ${ctx.spec.name} ws: connecting to ${ctx.spec.url}`);
|
|
45371
45238
|
const socket = await ctx.deps.transport(ctx.spec.url, {
|
|
45372
45239
|
onLine: guardLinkCallback(
|
|
@@ -45446,18 +45313,14 @@ var NodeLink = class {
|
|
|
45446
45313
|
this.ctx.disposed = true;
|
|
45447
45314
|
clearTimeout(this.ctx.reconnectTimer);
|
|
45448
45315
|
disconnectLink(this.ctx);
|
|
45449
|
-
this.ctx.tunnel?.dispose();
|
|
45450
45316
|
}
|
|
45451
45317
|
};
|
|
45452
45318
|
|
|
45453
45319
|
// 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
45320
|
function reconcileLinks(links2, specs, create) {
|
|
45458
45321
|
const wanted = new Map(specs.map((spec) => [spec.name, spec]));
|
|
45459
45322
|
for (const [name, link3] of links2) {
|
|
45460
|
-
if (
|
|
45323
|
+
if (wanted.get(name)?.url === link3.spec.url) {
|
|
45461
45324
|
link3.unlatch();
|
|
45462
45325
|
continue;
|
|
45463
45326
|
}
|
|
@@ -45467,7 +45330,7 @@ function reconcileLinks(links2, specs, create) {
|
|
|
45467
45330
|
}
|
|
45468
45331
|
for (const spec of specs) {
|
|
45469
45332
|
if (links2.has(spec.name)) continue;
|
|
45470
|
-
daemonLog(`link ${spec.name}: added (${
|
|
45333
|
+
daemonLog(`link ${spec.name}: added (${spec.url})`);
|
|
45471
45334
|
const link3 = create(spec);
|
|
45472
45335
|
links2.set(spec.name, link3);
|
|
45473
45336
|
link3.start();
|
|
@@ -45997,7 +45860,7 @@ function exitAfterFlush(code) {
|
|
|
45997
45860
|
}
|
|
45998
45861
|
|
|
45999
45862
|
// src/commands/sessions/daemon/handleConnection.ts
|
|
46000
|
-
import { createInterface as
|
|
45863
|
+
import { createInterface as createInterface10 } from "readline";
|
|
46001
45864
|
|
|
46002
45865
|
// src/commands/sessions/daemon/handleHelloRequest.ts
|
|
46003
45866
|
var handleHelloRequest = (client, m, d) => {
|
|
@@ -46012,10 +45875,10 @@ var handleHelloRequest = (client, m, d) => {
|
|
|
46012
45875
|
};
|
|
46013
45876
|
|
|
46014
45877
|
// src/commands/sessions/daemon/creator.ts
|
|
46015
|
-
function creator(isNew,
|
|
45878
|
+
function creator(isNew, spawn10) {
|
|
46016
45879
|
return (client, m, d) => {
|
|
46017
45880
|
if (m.links.route(client, d)) return;
|
|
46018
|
-
const result =
|
|
45881
|
+
const result = spawn10(m, d);
|
|
46019
45882
|
if (typeof result !== "string") {
|
|
46020
45883
|
sendTo(client, { type: "error", message: result.error });
|
|
46021
45884
|
return;
|
|
@@ -46583,7 +46446,7 @@ function handleConnection(socket, manager) {
|
|
|
46583
46446
|
};
|
|
46584
46447
|
manager.addClient(client);
|
|
46585
46448
|
manager.clients.greet(client);
|
|
46586
|
-
const lines2 =
|
|
46449
|
+
const lines2 = createInterface10({ input: socket });
|
|
46587
46450
|
lines2.on("error", () => {
|
|
46588
46451
|
});
|
|
46589
46452
|
lines2.on("line", (line) => {
|
|
@@ -46782,37 +46645,6 @@ function failed2(hop, error, remediation) {
|
|
|
46782
46645
|
return { hop, ok: false, error, remediation };
|
|
46783
46646
|
}
|
|
46784
46647
|
|
|
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
46648
|
// src/commands/sessions/nodes/fetchPeerJson.ts
|
|
46817
46649
|
var PEER_TIMEOUT_MS = 3e3;
|
|
46818
46650
|
function peerErrorCode(error) {
|
|
@@ -46899,45 +46731,6 @@ function linkStateHop(spec, probes) {
|
|
|
46899
46731
|
);
|
|
46900
46732
|
}
|
|
46901
46733
|
|
|
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
46734
|
// src/commands/sessions/nodes/findTailscalePeer.ts
|
|
46942
46735
|
function findTailscalePeer(status2, hostname2) {
|
|
46943
46736
|
const nodes = [
|
|
@@ -46988,18 +46781,6 @@ async function tailscaleHop(spec, probes) {
|
|
|
46988
46781
|
);
|
|
46989
46782
|
}
|
|
46990
46783
|
|
|
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
46784
|
// src/commands/sessions/nodes/tailscaleServeRemediation.ts
|
|
47004
46785
|
function tailscaleServeRemediation(spec, error) {
|
|
47005
46786
|
const status2 = error.status;
|
|
@@ -47016,8 +46797,6 @@ function isTailscaleLink(spec) {
|
|
|
47016
46797
|
|
|
47017
46798
|
// src/commands/sessions/nodes/webHop.ts
|
|
47018
46799
|
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
46800
|
const serve = isTailscaleLink(spec) ? tailscaleServeRemediation(spec, error) : void 0;
|
|
47022
46801
|
if (serve) return serve;
|
|
47023
46802
|
const { hostname: hostname2, port } = new URL(spec.url);
|
|
@@ -47047,7 +46826,7 @@ async function webHop(spec, probes) {
|
|
|
47047
46826
|
hop: failed2(
|
|
47048
46827
|
"web",
|
|
47049
46828
|
`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.
|
|
46829
|
+
`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
46830
|
)
|
|
47052
46831
|
};
|
|
47053
46832
|
return {
|
|
@@ -47073,17 +46852,6 @@ function peerDaemonHop(spec, health2) {
|
|
|
47073
46852
|
async function diagnoseLink(spec, probes) {
|
|
47074
46853
|
const hops = [];
|
|
47075
46854
|
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
46855
|
if (isTailscaleLink(spec)) {
|
|
47088
46856
|
hops.push(await tailscaleHop(spec, probes));
|
|
47089
46857
|
if (!hops.at(-1)?.ok) return done2();
|
|
@@ -47146,77 +46914,6 @@ async function probePeerHello(url) {
|
|
|
47146
46914
|
return result;
|
|
47147
46915
|
}
|
|
47148
46916
|
|
|
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
46917
|
// src/commands/sessions/nodes/printReport.ts
|
|
47221
46918
|
import chalk254 from "chalk";
|
|
47222
46919
|
function printReport(report2) {
|
|
@@ -47245,9 +46942,6 @@ function doctorProbes(live) {
|
|
|
47245
46942
|
return {
|
|
47246
46943
|
health: (url) => fetchPeerJson(url, "/api/health"),
|
|
47247
46944
|
hello: probePeerHello,
|
|
47248
|
-
sshAgent: probeSshAgent,
|
|
47249
|
-
ssh: probeSsh,
|
|
47250
|
-
tunnel: (localPort) => portAccepts(localPort),
|
|
47251
46945
|
tailscale: tailscaleStatus,
|
|
47252
46946
|
linkState: (name) => {
|
|
47253
46947
|
if (!live) return "no-daemon";
|
|
@@ -47329,7 +47023,7 @@ async function nodeLogs(name, options2) {
|
|
|
47329
47023
|
}
|
|
47330
47024
|
|
|
47331
47025
|
// src/commands/sessions/nodes/linkNode.ts
|
|
47332
|
-
import
|
|
47026
|
+
import chalk258 from "chalk";
|
|
47333
47027
|
|
|
47334
47028
|
// src/commands/sessions/nodes/notifyDaemonLinks.ts
|
|
47335
47029
|
import chalk256 from "chalk";
|
|
@@ -47355,11 +47049,10 @@ async function notifyDaemonLinks() {
|
|
|
47355
47049
|
}
|
|
47356
47050
|
}
|
|
47357
47051
|
|
|
47052
|
+
// src/commands/sessions/nodes/readLinks.ts
|
|
47053
|
+
import chalk257 from "chalk";
|
|
47054
|
+
|
|
47358
47055
|
// src/commands/sessions/nodes/writeLinks.ts
|
|
47359
|
-
function readLinks() {
|
|
47360
|
-
const sessions = loadGlobalConfigRaw().sessions;
|
|
47361
|
-
return sessions?.links ?? [];
|
|
47362
|
-
}
|
|
47363
47056
|
async function writeLinks(links2) {
|
|
47364
47057
|
const config = loadGlobalConfigRaw();
|
|
47365
47058
|
const sessions = { ...config.sessions };
|
|
@@ -47371,6 +47064,20 @@ async function writeLinks(links2) {
|
|
|
47371
47064
|
saveGlobalConfig(updated2);
|
|
47372
47065
|
}
|
|
47373
47066
|
|
|
47067
|
+
// src/commands/sessions/nodes/readLinks.ts
|
|
47068
|
+
async function readLinks() {
|
|
47069
|
+
const sessions = loadGlobalConfigRaw().sessions;
|
|
47070
|
+
const stored = sessions?.links ?? [];
|
|
47071
|
+
const links2 = stored.filter((link3) => !!link3.url);
|
|
47072
|
+
if (links2.length === stored.length) return links2;
|
|
47073
|
+
await writeLinks(links2);
|
|
47074
|
+
const dropped = stored.filter((link3) => !link3.url).map((link3) => link3.name);
|
|
47075
|
+
console.log(
|
|
47076
|
+
chalk257.yellow(`Removed ${dropped.join(", ")}: ${SSH_LINK_RETIRED}`)
|
|
47077
|
+
);
|
|
47078
|
+
return links2;
|
|
47079
|
+
}
|
|
47080
|
+
|
|
47374
47081
|
// src/commands/sessions/nodes/tailscaleLinkUrl.ts
|
|
47375
47082
|
async function localTailnetSuffix() {
|
|
47376
47083
|
return tailnetSuffix(await tailscaleStatus());
|
|
@@ -47399,82 +47106,54 @@ function parseLinkUrl(url) {
|
|
|
47399
47106
|
}
|
|
47400
47107
|
|
|
47401
47108
|
// 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
|
-
);
|
|
47109
|
+
async function buildLink(name, url, options2, resolveTailnetSuffix) {
|
|
47110
|
+
if (url && options2.tailscale)
|
|
47111
|
+
throw new Error("pass only one of <url> or --tailscale <host>");
|
|
47407
47112
|
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)
|
|
47113
|
+
if (!options2.tailscale)
|
|
47420
47114
|
throw new Error(
|
|
47421
|
-
"pass the peer's <url
|
|
47115
|
+
"pass the peer's <url> or --tailscale <host> --port <port>"
|
|
47422
47116
|
);
|
|
47423
47117
|
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;
|
|
47118
|
+
return {
|
|
47119
|
+
name,
|
|
47120
|
+
url: await tailscaleLinkUrl(options2.tailscale, port, resolveTailnetSuffix)
|
|
47121
|
+
};
|
|
47432
47122
|
}
|
|
47433
47123
|
|
|
47434
47124
|
// src/commands/sessions/nodes/linkNode.ts
|
|
47435
47125
|
async function linkNode(name, url, options2) {
|
|
47436
47126
|
if (name.includes(":")) throw new Error("node names cannot contain ':'");
|
|
47127
|
+
const others = (await readLinks()).filter((link4) => link4.name !== name);
|
|
47437
47128
|
if (name === resolveNodeName())
|
|
47438
47129
|
throw new Error(`${name} is this node; link to a different node`);
|
|
47439
|
-
const
|
|
47440
|
-
const link3 = await buildLink(name, url, options2, others);
|
|
47130
|
+
const link3 = await buildLink(name, url, options2);
|
|
47441
47131
|
await writeLinks([...others, link3]);
|
|
47442
|
-
console.log(
|
|
47443
|
-
chalk257.green(`Linked ${name} (${describeTarget(toLinkSpec(link3))})`)
|
|
47444
|
-
);
|
|
47132
|
+
console.log(chalk258.green(`Linked ${name} (${link3.url})`));
|
|
47445
47133
|
await notifyDaemonLinks();
|
|
47446
47134
|
}
|
|
47447
47135
|
|
|
47448
47136
|
// src/commands/sessions/nodes/registerLinkCommand.ts
|
|
47449
47137
|
function registerLinkCommand(nodes) {
|
|
47450
47138
|
nodes.command("link <name> [url]").description(
|
|
47451
|
-
"Link a peer node by its web server URL
|
|
47139
|
+
"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
47140
|
).option(
|
|
47453
47141
|
"--tailscale <host>",
|
|
47454
47142
|
"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);
|
|
47143
|
+
).option("--port <port>", "The peer's web server port (with --tailscale)").action(linkNode);
|
|
47465
47144
|
}
|
|
47466
47145
|
|
|
47467
47146
|
// src/commands/sessions/nodes/unlinkNode.ts
|
|
47468
|
-
import
|
|
47147
|
+
import chalk259 from "chalk";
|
|
47469
47148
|
async function unlinkNode(name) {
|
|
47470
|
-
const links2 = readLinks();
|
|
47149
|
+
const links2 = await readLinks();
|
|
47471
47150
|
const remaining = links2.filter((link3) => link3.name !== name);
|
|
47472
47151
|
if (remaining.length === links2.length) {
|
|
47473
|
-
console.log(
|
|
47152
|
+
console.log(chalk259.yellow(`No link named ${name}`));
|
|
47474
47153
|
return;
|
|
47475
47154
|
}
|
|
47476
47155
|
await writeLinks(remaining);
|
|
47477
|
-
console.log(
|
|
47156
|
+
console.log(chalk259.green(`Unlinked ${name}`));
|
|
47478
47157
|
await notifyDaemonLinks();
|
|
47479
47158
|
}
|
|
47480
47159
|
|
|
@@ -47495,14 +47174,14 @@ function registerNodes(sessions) {
|
|
|
47495
47174
|
}
|
|
47496
47175
|
|
|
47497
47176
|
// src/commands/sessions/daemon/requestSessionOutput.ts
|
|
47498
|
-
import { createInterface as
|
|
47177
|
+
import { createInterface as createInterface11 } from "readline";
|
|
47499
47178
|
var OUTPUT_TIMEOUT_MS = 5e3;
|
|
47500
47179
|
async function requestSessionOutput(target) {
|
|
47501
47180
|
const socket = await connectToDaemon().catch(() => {
|
|
47502
47181
|
throw new Error("No sessions daemon is running");
|
|
47503
47182
|
});
|
|
47504
47183
|
try {
|
|
47505
|
-
const lines2 =
|
|
47184
|
+
const lines2 = createInterface11({ input: socket });
|
|
47506
47185
|
lines2.on("error", () => {
|
|
47507
47186
|
});
|
|
47508
47187
|
const reply2 = readDaemonMessage(
|
|
@@ -47605,7 +47284,7 @@ async function renameSession(title) {
|
|
|
47605
47284
|
|
|
47606
47285
|
// src/commands/sessions/summarise.ts
|
|
47607
47286
|
import * as fs58 from "fs";
|
|
47608
|
-
import
|
|
47287
|
+
import chalk260 from "chalk";
|
|
47609
47288
|
|
|
47610
47289
|
// src/commands/sessions/summarise/shared.ts
|
|
47611
47290
|
import * as fs57 from "fs";
|
|
@@ -47664,22 +47343,22 @@ ${firstMessage}`);
|
|
|
47664
47343
|
async function summarise2(options2) {
|
|
47665
47344
|
const files = await discoverSessionFiles();
|
|
47666
47345
|
if (files.length === 0) {
|
|
47667
|
-
console.log(
|
|
47346
|
+
console.log(chalk260.yellow("No sessions found."));
|
|
47668
47347
|
return;
|
|
47669
47348
|
}
|
|
47670
47349
|
const toProcess = selectCandidates(files, options2);
|
|
47671
47350
|
if (toProcess.length === 0) {
|
|
47672
|
-
console.log(
|
|
47351
|
+
console.log(chalk260.green("All sessions already summarised."));
|
|
47673
47352
|
return;
|
|
47674
47353
|
}
|
|
47675
47354
|
console.log(
|
|
47676
|
-
|
|
47355
|
+
chalk260.cyan(
|
|
47677
47356
|
`Summarising ${toProcess.length} session(s) (${files.length} total)\u2026`
|
|
47678
47357
|
)
|
|
47679
47358
|
);
|
|
47680
47359
|
const { succeeded, failed: failed3 } = processSessions(toProcess);
|
|
47681
47360
|
console.log(
|
|
47682
|
-
|
|
47361
|
+
chalk260.green(`Done: ${succeeded} summarised`) + (failed3 > 0 ? chalk260.yellow(`, ${failed3} skipped`) : "")
|
|
47683
47362
|
);
|
|
47684
47363
|
}
|
|
47685
47364
|
function selectCandidates(files, options2) {
|
|
@@ -47699,16 +47378,16 @@ function processSessions(files) {
|
|
|
47699
47378
|
let failed3 = 0;
|
|
47700
47379
|
for (let i = 0; i < files.length; i++) {
|
|
47701
47380
|
const file = files[i];
|
|
47702
|
-
process.stdout.write(
|
|
47381
|
+
process.stdout.write(chalk260.dim(` [${i + 1}/${files.length}] `));
|
|
47703
47382
|
const summary = summariseSession(file);
|
|
47704
47383
|
if (summary) {
|
|
47705
47384
|
writeSummary(file, summary);
|
|
47706
47385
|
succeeded++;
|
|
47707
|
-
process.stdout.write(`${
|
|
47386
|
+
process.stdout.write(`${chalk260.green("\u2713")} ${summary}
|
|
47708
47387
|
`);
|
|
47709
47388
|
} else {
|
|
47710
47389
|
failed3++;
|
|
47711
|
-
process.stdout.write(` ${
|
|
47390
|
+
process.stdout.write(` ${chalk260.yellow("skip")}
|
|
47712
47391
|
`);
|
|
47713
47392
|
}
|
|
47714
47393
|
}
|
|
@@ -47738,10 +47417,10 @@ function registerSessions(program2) {
|
|
|
47738
47417
|
}
|
|
47739
47418
|
|
|
47740
47419
|
// src/reportCliError.ts
|
|
47741
|
-
import
|
|
47420
|
+
import chalk261 from "chalk";
|
|
47742
47421
|
function reportCliError(error) {
|
|
47743
47422
|
if (error instanceof InvalidItemIdError || error instanceof AmbiguousRepoConfigError || error instanceof UnknownRepoConfigError || error instanceof MissingRunCwdError || error instanceof MiroExtractError) {
|
|
47744
|
-
console.error(
|
|
47423
|
+
console.error(chalk261.red(error.message));
|
|
47745
47424
|
} else {
|
|
47746
47425
|
console.error(error);
|
|
47747
47426
|
}
|