@zenalexa/unicli 0.224.0 → 0.224.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/AGENTS.md +5 -5
- package/README.md +3 -3
- package/README.zh-CN.md +3 -3
- package/dist/adapters/marxists-cn/archive.d.ts +61 -0
- package/dist/adapters/marxists-cn/archive.d.ts.map +1 -0
- package/dist/adapters/marxists-cn/archive.js +861 -0
- package/dist/adapters/marxists-cn/archive.js.map +1 -0
- package/dist/adapters/twitter/lists-extra.d.ts +17 -1
- package/dist/adapters/twitter/lists-extra.d.ts.map +1 -1
- package/dist/adapters/twitter/lists-extra.js +123 -21
- package/dist/adapters/twitter/lists-extra.js.map +1 -1
- package/dist/adapters/twitter/post.js +1 -0
- package/dist/adapters/twitter/post.js.map +1 -1
- package/dist/adapters/twitter/thread.d.ts +13 -1
- package/dist/adapters/twitter/thread.d.ts.map +1 -1
- package/dist/adapters/twitter/thread.js +76 -33
- package/dist/adapters/twitter/thread.js.map +1 -1
- package/dist/discovery/aliases.d.ts.map +1 -1
- package/dist/discovery/aliases.js +93 -0
- package/dist/discovery/aliases.js.map +1 -1
- package/dist/discovery/intents.d.ts.map +1 -1
- package/dist/discovery/intents.js +124 -0
- package/dist/discovery/intents.js.map +1 -1
- package/dist/engine/text-normalize.d.ts +14 -0
- package/dist/engine/text-normalize.d.ts.map +1 -1
- package/dist/engine/text-normalize.js +64 -0
- package/dist/engine/text-normalize.js.map +1 -1
- package/dist/manifest-compact.txt +2 -2
- package/dist/manifest.json +352 -3
- package/package.json +1 -1
- package/server.json +2 -2
- package/skills/unicli/SKILL.md +1 -1
- package/skills/unicli-claude-code/SKILL.md +1 -1
- package/skills/unicli-hermes/SKILL.md +1 -1
- package/src/adapters/marxists-cn/archive.test.ts +173 -0
- package/src/adapters/marxists-cn/archive.ts +1049 -0
- package/src/adapters/twitter/lists-extra.test.ts +115 -0
- package/src/adapters/twitter/lists-extra.ts +146 -26
- package/src/adapters/twitter/post.ts +1 -0
- package/src/adapters/twitter/thread.test.ts +25 -1
- package/src/adapters/twitter/thread.ts +99 -47
package/dist/manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.224.
|
|
2
|
+
"version": "0.224.1",
|
|
3
3
|
"sites": {
|
|
4
4
|
"1688": {
|
|
5
5
|
"commands": [
|
|
@@ -26661,6 +26661,251 @@
|
|
|
26661
26661
|
],
|
|
26662
26662
|
"category": "shopping"
|
|
26663
26663
|
},
|
|
26664
|
+
"marxists-cn": {
|
|
26665
|
+
"commands": [
|
|
26666
|
+
{
|
|
26667
|
+
"name": "authors",
|
|
26668
|
+
"description": "List people, authors, organizations, and topic directories in the Chinese Marxists archive",
|
|
26669
|
+
"strategy": "public",
|
|
26670
|
+
"type": "web-api",
|
|
26671
|
+
"columns": [
|
|
26672
|
+
"rank",
|
|
26673
|
+
"title",
|
|
26674
|
+
"latinName",
|
|
26675
|
+
"kind",
|
|
26676
|
+
"path",
|
|
26677
|
+
"url"
|
|
26678
|
+
],
|
|
26679
|
+
"args": [
|
|
26680
|
+
{
|
|
26681
|
+
"name": "limit",
|
|
26682
|
+
"type": "int",
|
|
26683
|
+
"default": 120,
|
|
26684
|
+
"description": "Max rows"
|
|
26685
|
+
}
|
|
26686
|
+
],
|
|
26687
|
+
"pipeline_steps": 0,
|
|
26688
|
+
"adapter_path": "src/adapters/marxists-cn/archive.ts",
|
|
26689
|
+
"target_surface": ""
|
|
26690
|
+
},
|
|
26691
|
+
{
|
|
26692
|
+
"name": "index",
|
|
26693
|
+
"description": "List Chinese Marxists Internet Archive top-level people, topics, and library links",
|
|
26694
|
+
"strategy": "public",
|
|
26695
|
+
"type": "web-api",
|
|
26696
|
+
"columns": [
|
|
26697
|
+
"rank",
|
|
26698
|
+
"title",
|
|
26699
|
+
"latinName",
|
|
26700
|
+
"kind",
|
|
26701
|
+
"path",
|
|
26702
|
+
"url"
|
|
26703
|
+
],
|
|
26704
|
+
"args": [
|
|
26705
|
+
{
|
|
26706
|
+
"name": "limit",
|
|
26707
|
+
"type": "int",
|
|
26708
|
+
"default": 80,
|
|
26709
|
+
"description": "Max rows"
|
|
26710
|
+
}
|
|
26711
|
+
],
|
|
26712
|
+
"pipeline_steps": 0,
|
|
26713
|
+
"adapter_path": "src/adapters/marxists-cn/archive.ts",
|
|
26714
|
+
"target_surface": ""
|
|
26715
|
+
},
|
|
26716
|
+
{
|
|
26717
|
+
"name": "read",
|
|
26718
|
+
"description": "Read a Chinese Marxists archive HTML page as clean plain text",
|
|
26719
|
+
"strategy": "public",
|
|
26720
|
+
"type": "web-api",
|
|
26721
|
+
"columns": [
|
|
26722
|
+
"title",
|
|
26723
|
+
"author",
|
|
26724
|
+
"date",
|
|
26725
|
+
"chars",
|
|
26726
|
+
"text",
|
|
26727
|
+
"url"
|
|
26728
|
+
],
|
|
26729
|
+
"args": [
|
|
26730
|
+
{
|
|
26731
|
+
"name": "path",
|
|
26732
|
+
"type": "str",
|
|
26733
|
+
"required": true,
|
|
26734
|
+
"positional": true,
|
|
26735
|
+
"description": "Archive path or URL under /chinese/"
|
|
26736
|
+
},
|
|
26737
|
+
{
|
|
26738
|
+
"name": "max-length",
|
|
26739
|
+
"type": "int",
|
|
26740
|
+
"default": 30000,
|
|
26741
|
+
"description": "Max text characters"
|
|
26742
|
+
}
|
|
26743
|
+
],
|
|
26744
|
+
"pipeline_steps": 0,
|
|
26745
|
+
"adapter_path": "src/adapters/marxists-cn/archive.ts",
|
|
26746
|
+
"target_surface": ""
|
|
26747
|
+
},
|
|
26748
|
+
{
|
|
26749
|
+
"name": "reading-list",
|
|
26750
|
+
"description": "Return curated Chinese Marxists archive reading lists with directly readable paths",
|
|
26751
|
+
"strategy": "public",
|
|
26752
|
+
"type": "web-api",
|
|
26753
|
+
"columns": [
|
|
26754
|
+
"rank",
|
|
26755
|
+
"preset",
|
|
26756
|
+
"author",
|
|
26757
|
+
"title",
|
|
26758
|
+
"year",
|
|
26759
|
+
"theme",
|
|
26760
|
+
"path",
|
|
26761
|
+
"url",
|
|
26762
|
+
"readCommand",
|
|
26763
|
+
"note"
|
|
26764
|
+
],
|
|
26765
|
+
"args": [
|
|
26766
|
+
{
|
|
26767
|
+
"name": "preset",
|
|
26768
|
+
"type": "str",
|
|
26769
|
+
"required": true,
|
|
26770
|
+
"positional": true,
|
|
26771
|
+
"description": "Reading list preset, currently western-marxism"
|
|
26772
|
+
},
|
|
26773
|
+
{
|
|
26774
|
+
"name": "limit",
|
|
26775
|
+
"type": "int",
|
|
26776
|
+
"default": 40,
|
|
26777
|
+
"description": "Max rows"
|
|
26778
|
+
}
|
|
26779
|
+
],
|
|
26780
|
+
"pipeline_steps": 0,
|
|
26781
|
+
"adapter_path": "src/adapters/marxists-cn/archive.ts",
|
|
26782
|
+
"target_surface": ""
|
|
26783
|
+
},
|
|
26784
|
+
{
|
|
26785
|
+
"name": "search",
|
|
26786
|
+
"description": "Search Chinese Marxists archive people, books, works, and scoped full text",
|
|
26787
|
+
"strategy": "public",
|
|
26788
|
+
"type": "web-api",
|
|
26789
|
+
"columns": [
|
|
26790
|
+
"rank",
|
|
26791
|
+
"type",
|
|
26792
|
+
"scope",
|
|
26793
|
+
"section",
|
|
26794
|
+
"title",
|
|
26795
|
+
"snippet",
|
|
26796
|
+
"path",
|
|
26797
|
+
"url",
|
|
26798
|
+
"score"
|
|
26799
|
+
],
|
|
26800
|
+
"args": [
|
|
26801
|
+
{
|
|
26802
|
+
"name": "query",
|
|
26803
|
+
"type": "str",
|
|
26804
|
+
"required": true,
|
|
26805
|
+
"positional": true,
|
|
26806
|
+
"description": "Chinese or English search text"
|
|
26807
|
+
},
|
|
26808
|
+
{
|
|
26809
|
+
"name": "limit",
|
|
26810
|
+
"type": "int",
|
|
26811
|
+
"default": 20,
|
|
26812
|
+
"description": "Max rows"
|
|
26813
|
+
},
|
|
26814
|
+
{
|
|
26815
|
+
"name": "scope",
|
|
26816
|
+
"type": "str",
|
|
26817
|
+
"default": "",
|
|
26818
|
+
"description": "Optional author/topic path for focused search, e.g. marx"
|
|
26819
|
+
},
|
|
26820
|
+
{
|
|
26821
|
+
"name": "scan-pages",
|
|
26822
|
+
"type": "int",
|
|
26823
|
+
"default": 24,
|
|
26824
|
+
"description": "Top-level index pages to scan when scope is omitted"
|
|
26825
|
+
},
|
|
26826
|
+
{
|
|
26827
|
+
"name": "full-text",
|
|
26828
|
+
"type": "bool",
|
|
26829
|
+
"default": false,
|
|
26830
|
+
"description": "When true, search text inside scoped HTML work pages"
|
|
26831
|
+
},
|
|
26832
|
+
{
|
|
26833
|
+
"name": "content-pages",
|
|
26834
|
+
"type": "int",
|
|
26835
|
+
"default": 40,
|
|
26836
|
+
"description": "Max HTML pages to read for full-text scoped search"
|
|
26837
|
+
}
|
|
26838
|
+
],
|
|
26839
|
+
"pipeline_steps": 0,
|
|
26840
|
+
"adapter_path": "src/adapters/marxists-cn/archive.ts",
|
|
26841
|
+
"target_surface": ""
|
|
26842
|
+
},
|
|
26843
|
+
{
|
|
26844
|
+
"name": "western-marxism",
|
|
26845
|
+
"description": "List famous Western Marxist authors and works from the Chinese Marxists archive with read commands",
|
|
26846
|
+
"strategy": "public",
|
|
26847
|
+
"type": "web-api",
|
|
26848
|
+
"columns": [
|
|
26849
|
+
"rank",
|
|
26850
|
+
"preset",
|
|
26851
|
+
"author",
|
|
26852
|
+
"title",
|
|
26853
|
+
"year",
|
|
26854
|
+
"theme",
|
|
26855
|
+
"path",
|
|
26856
|
+
"url",
|
|
26857
|
+
"readCommand",
|
|
26858
|
+
"note"
|
|
26859
|
+
],
|
|
26860
|
+
"args": [
|
|
26861
|
+
{
|
|
26862
|
+
"name": "limit",
|
|
26863
|
+
"type": "int",
|
|
26864
|
+
"default": 40,
|
|
26865
|
+
"description": "Max rows"
|
|
26866
|
+
}
|
|
26867
|
+
],
|
|
26868
|
+
"pipeline_steps": 0,
|
|
26869
|
+
"adapter_path": "src/adapters/marxists-cn/archive.ts",
|
|
26870
|
+
"target_surface": ""
|
|
26871
|
+
},
|
|
26872
|
+
{
|
|
26873
|
+
"name": "works",
|
|
26874
|
+
"description": "List works/books/articles under a Chinese Marxists archive author or topic path",
|
|
26875
|
+
"strategy": "public",
|
|
26876
|
+
"type": "web-api",
|
|
26877
|
+
"columns": [
|
|
26878
|
+
"rank",
|
|
26879
|
+
"scope",
|
|
26880
|
+
"section",
|
|
26881
|
+
"title",
|
|
26882
|
+
"note",
|
|
26883
|
+
"format",
|
|
26884
|
+
"path",
|
|
26885
|
+
"url"
|
|
26886
|
+
],
|
|
26887
|
+
"args": [
|
|
26888
|
+
{
|
|
26889
|
+
"name": "scope",
|
|
26890
|
+
"type": "str",
|
|
26891
|
+
"required": true,
|
|
26892
|
+
"positional": true,
|
|
26893
|
+
"description": "Author/topic path, e.g. marx, lenin, georg-lukacs"
|
|
26894
|
+
},
|
|
26895
|
+
{
|
|
26896
|
+
"name": "limit",
|
|
26897
|
+
"type": "int",
|
|
26898
|
+
"default": 120,
|
|
26899
|
+
"description": "Max rows"
|
|
26900
|
+
}
|
|
26901
|
+
],
|
|
26902
|
+
"pipeline_steps": 0,
|
|
26903
|
+
"adapter_path": "src/adapters/marxists-cn/archive.ts",
|
|
26904
|
+
"target_surface": ""
|
|
26905
|
+
}
|
|
26906
|
+
],
|
|
26907
|
+
"category": "reference"
|
|
26908
|
+
},
|
|
26664
26909
|
"mastodon": {
|
|
26665
26910
|
"commands": [
|
|
26666
26911
|
{
|
|
@@ -39748,6 +39993,36 @@
|
|
|
39748
39993
|
"adapter_path": "src/adapters/twitter/bookmarks.ts",
|
|
39749
39994
|
"target_surface": ""
|
|
39750
39995
|
},
|
|
39996
|
+
{
|
|
39997
|
+
"name": "comments",
|
|
39998
|
+
"description": "Get replies/comments for a Twitter/X tweet",
|
|
39999
|
+
"strategy": "cookie",
|
|
40000
|
+
"type": "web-api",
|
|
40001
|
+
"domain": "x.com",
|
|
40002
|
+
"columns": [
|
|
40003
|
+
"id",
|
|
40004
|
+
"parent_id",
|
|
40005
|
+
"author",
|
|
40006
|
+
"text",
|
|
40007
|
+
"likes",
|
|
40008
|
+
"retweets",
|
|
40009
|
+
"views",
|
|
40010
|
+
"url",
|
|
40011
|
+
"depth",
|
|
40012
|
+
"path"
|
|
40013
|
+
],
|
|
40014
|
+
"args": [
|
|
40015
|
+
{
|
|
40016
|
+
"name": "url",
|
|
40017
|
+
"required": true,
|
|
40018
|
+
"positional": true,
|
|
40019
|
+
"description": "Tweet ID or Twitter/X status URL"
|
|
40020
|
+
}
|
|
40021
|
+
],
|
|
40022
|
+
"pipeline_steps": 0,
|
|
40023
|
+
"adapter_path": "src/adapters/twitter/thread.ts",
|
|
40024
|
+
"target_surface": ""
|
|
40025
|
+
},
|
|
39751
40026
|
{
|
|
39752
40027
|
"name": "delete",
|
|
39753
40028
|
"description": "Delete your own tweet",
|
|
@@ -39999,14 +40274,18 @@
|
|
|
39999
40274
|
},
|
|
40000
40275
|
{
|
|
40001
40276
|
"name": "list-tweets",
|
|
40002
|
-
"description": "Read tweets from a Twitter/X list",
|
|
40277
|
+
"description": "Read tweets from a Twitter/X list timeline",
|
|
40003
40278
|
"strategy": "cookie",
|
|
40004
40279
|
"type": "web-api",
|
|
40005
40280
|
"domain": "x.com",
|
|
40006
40281
|
"browser": true,
|
|
40007
40282
|
"columns": [
|
|
40283
|
+
"id",
|
|
40008
40284
|
"author",
|
|
40009
40285
|
"text",
|
|
40286
|
+
"likes",
|
|
40287
|
+
"retweets",
|
|
40288
|
+
"views",
|
|
40010
40289
|
"url"
|
|
40011
40290
|
],
|
|
40012
40291
|
"args": [
|
|
@@ -40528,7 +40807,7 @@
|
|
|
40528
40807
|
"name": "tweet_id",
|
|
40529
40808
|
"required": true,
|
|
40530
40809
|
"positional": true,
|
|
40531
|
-
"description": "Tweet ID
|
|
40810
|
+
"description": "Tweet ID or Twitter/X status URL"
|
|
40532
40811
|
}
|
|
40533
40812
|
],
|
|
40534
40813
|
"pipeline_steps": 0,
|
|
@@ -40587,8 +40866,12 @@
|
|
|
40587
40866
|
"domain": "x.com",
|
|
40588
40867
|
"browser": true,
|
|
40589
40868
|
"columns": [
|
|
40869
|
+
"id",
|
|
40590
40870
|
"author",
|
|
40591
40871
|
"text",
|
|
40872
|
+
"likes",
|
|
40873
|
+
"retweets",
|
|
40874
|
+
"views",
|
|
40592
40875
|
"url"
|
|
40593
40876
|
],
|
|
40594
40877
|
"args": [
|
|
@@ -40745,6 +41028,72 @@
|
|
|
40745
41028
|
"pipeline_steps": 0,
|
|
40746
41029
|
"adapter_path": "src/adapters/twitter/tweet-actions.ts",
|
|
40747
41030
|
"target_surface": ""
|
|
41031
|
+
},
|
|
41032
|
+
{
|
|
41033
|
+
"name": "user-timeline",
|
|
41034
|
+
"description": "Read a Twitter/X user's tweet timeline",
|
|
41035
|
+
"strategy": "cookie",
|
|
41036
|
+
"type": "web-api",
|
|
41037
|
+
"domain": "x.com",
|
|
41038
|
+
"browser": true,
|
|
41039
|
+
"columns": [
|
|
41040
|
+
"id",
|
|
41041
|
+
"author",
|
|
41042
|
+
"text",
|
|
41043
|
+
"likes",
|
|
41044
|
+
"retweets",
|
|
41045
|
+
"views",
|
|
41046
|
+
"url"
|
|
41047
|
+
],
|
|
41048
|
+
"args": [
|
|
41049
|
+
{
|
|
41050
|
+
"name": "user",
|
|
41051
|
+
"type": "str",
|
|
41052
|
+
"required": true,
|
|
41053
|
+
"positional": true
|
|
41054
|
+
},
|
|
41055
|
+
{
|
|
41056
|
+
"name": "limit",
|
|
41057
|
+
"type": "int",
|
|
41058
|
+
"default": 20
|
|
41059
|
+
}
|
|
41060
|
+
],
|
|
41061
|
+
"pipeline_steps": 0,
|
|
41062
|
+
"adapter_path": "src/adapters/twitter/lists-extra.ts",
|
|
41063
|
+
"target_surface": ""
|
|
41064
|
+
},
|
|
41065
|
+
{
|
|
41066
|
+
"name": "user-tweets",
|
|
41067
|
+
"description": "Read recent tweets from a Twitter/X user profile",
|
|
41068
|
+
"strategy": "cookie",
|
|
41069
|
+
"type": "web-api",
|
|
41070
|
+
"domain": "x.com",
|
|
41071
|
+
"browser": true,
|
|
41072
|
+
"columns": [
|
|
41073
|
+
"id",
|
|
41074
|
+
"author",
|
|
41075
|
+
"text",
|
|
41076
|
+
"likes",
|
|
41077
|
+
"retweets",
|
|
41078
|
+
"views",
|
|
41079
|
+
"url"
|
|
41080
|
+
],
|
|
41081
|
+
"args": [
|
|
41082
|
+
{
|
|
41083
|
+
"name": "user",
|
|
41084
|
+
"type": "str",
|
|
41085
|
+
"required": true,
|
|
41086
|
+
"positional": true
|
|
41087
|
+
},
|
|
41088
|
+
{
|
|
41089
|
+
"name": "limit",
|
|
41090
|
+
"type": "int",
|
|
41091
|
+
"default": 20
|
|
41092
|
+
}
|
|
41093
|
+
],
|
|
41094
|
+
"pipeline_steps": 0,
|
|
41095
|
+
"adapter_path": "src/adapters/twitter/lists-extra.ts",
|
|
41096
|
+
"target_surface": ""
|
|
40748
41097
|
}
|
|
40749
41098
|
],
|
|
40750
41099
|
"category": "social"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenalexa/unicli",
|
|
3
|
-
"version": "0.224.
|
|
3
|
+
"version": "0.224.1",
|
|
4
4
|
"description": "Operations substrate for agents that use real software: web, browsers, desktop apps, local tools, MCP, policy, evidence, and self-repair.",
|
|
5
5
|
"packageManager": "npm@11.14.0",
|
|
6
6
|
"type": "module",
|
package/server.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
|
|
3
3
|
"name": "io.github.olo-dot-io/Uni-CLI",
|
|
4
4
|
"description": "Self-repairing CLI catalog that exposes 311 websites, desktop apps, and external CLIs as one MCP server. 977 declarative YAML adapters and 1753 commands; structured error envelopes let agents fix failing adapters at runtime and retry.",
|
|
5
|
-
"version": "0.224.
|
|
5
|
+
"version": "0.224.1",
|
|
6
6
|
"repository": {
|
|
7
7
|
"url": "https://github.com/olo-dot-io/Uni-CLI",
|
|
8
8
|
"source": "github"
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
15
15
|
"identifier": "@zenalexa/unicli",
|
|
16
|
-
"version": "0.224.
|
|
16
|
+
"version": "0.224.1",
|
|
17
17
|
"transport": {
|
|
18
18
|
"type": "stdio"
|
|
19
19
|
},
|
package/skills/unicli/SKILL.md
CHANGED
|
@@ -11,7 +11,7 @@ description: >
|
|
|
11
11
|
major platform; run desktop workflows or system tasks; or when the user says
|
|
12
12
|
"unicli", "scrape", "fetch from", "get trending", "check [site]", "find on
|
|
13
13
|
[platform]", "获取", "查询", "抓取".
|
|
14
|
-
version: 0.224.
|
|
14
|
+
version: 0.224.1
|
|
15
15
|
category: core
|
|
16
16
|
depends-on:
|
|
17
17
|
- talk-normal
|
|
@@ -6,7 +6,7 @@ description: >
|
|
|
6
6
|
newlines, or inline JSON — shell-quoted invocations hit TC0 circuit
|
|
7
7
|
limits and drop to <50% success above ICS=4. Also covers --describe
|
|
8
8
|
introspection and next_actions-driven navigation.
|
|
9
|
-
version: 0.224.
|
|
9
|
+
version: 0.224.1
|
|
10
10
|
depends-on:
|
|
11
11
|
- talk-normal
|
|
12
12
|
triggers:
|
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
Use Uni-CLI to interact with 237 websites, desktop apps, and system tools.
|
|
5
5
|
Trigger when: user asks to check a website, fetch data, control a desktop app,
|
|
6
6
|
or interact with social media, news, finance, or AI platforms.
|
|
7
|
-
version: 0.224.
|
|
7
|
+
version: 0.224.1
|
|
8
8
|
depends-on:
|
|
9
9
|
- talk-normal
|
|
10
10
|
triggers:
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
decodeMarxistsBuffer,
|
|
4
|
+
mapMarxistsReadRow,
|
|
5
|
+
marxistsHtmlToText,
|
|
6
|
+
marxistsReadingListRows,
|
|
7
|
+
normalizeMarxistsPath,
|
|
8
|
+
parseMarxistsIndex,
|
|
9
|
+
parseMarxistsWorks,
|
|
10
|
+
requireMarxistsLimit,
|
|
11
|
+
} from "./archive.js";
|
|
12
|
+
|
|
13
|
+
describe("marxists-cn agent-facing archive adapter", () => {
|
|
14
|
+
it("normalizes paths and rejects off-archive URLs", () => {
|
|
15
|
+
expect(normalizeMarxistsPath("marx", { directoryIndex: true })).toBe(
|
|
16
|
+
"marx/index.htm",
|
|
17
|
+
);
|
|
18
|
+
expect(
|
|
19
|
+
normalizeMarxistsPath("https://www.marxists.org/chinese/marx/01.htm#8"),
|
|
20
|
+
).toBe("marx/01.htm");
|
|
21
|
+
expect(() =>
|
|
22
|
+
normalizeMarxistsPath("https://example.com/chinese/marx/01.htm"),
|
|
23
|
+
).toThrow("must stay on www.marxists.org");
|
|
24
|
+
expect(() => normalizeMarxistsPath("../index.htm")).toThrow(
|
|
25
|
+
"must stay under /chinese/",
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("validates bounded integer arguments", () => {
|
|
30
|
+
expect(requireMarxistsLimit(undefined, 20, 100, "limit")).toBe(20);
|
|
31
|
+
expect(requireMarxistsLimit("5", 20, 100, "limit")).toBe(5);
|
|
32
|
+
expect(() => requireMarxistsLimit("0", 20, 100, "limit")).toThrow(
|
|
33
|
+
"marxists-cn limit must",
|
|
34
|
+
);
|
|
35
|
+
expect(() => requireMarxistsLimit("101", 20, 100, "limit")).toThrow(
|
|
36
|
+
"marxists-cn limit must",
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("parses top-level people and reference links from the Chinese index", () => {
|
|
41
|
+
const rows = parseMarxistsIndex(`
|
|
42
|
+
<a title="马克思 Karl Marx" href="marx/index.htm">
|
|
43
|
+
<img src="images/1-marx.jpg" alt="马克思">
|
|
44
|
+
</a>
|
|
45
|
+
<a href="abc/index.htm">马克思主义简介</a>
|
|
46
|
+
<a href="search/index.html">中文马克思主义文库搜索</a>
|
|
47
|
+
`);
|
|
48
|
+
|
|
49
|
+
expect(rows).toEqual([
|
|
50
|
+
{
|
|
51
|
+
title: "马克思",
|
|
52
|
+
latinName: "Karl Marx",
|
|
53
|
+
kind: "directory",
|
|
54
|
+
path: "marx/index.htm",
|
|
55
|
+
url: "https://www.marxists.org/chinese/marx/index.htm",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
title: "马克思主义简介",
|
|
59
|
+
latinName: "",
|
|
60
|
+
kind: "reference",
|
|
61
|
+
path: "abc/index.htm",
|
|
62
|
+
url: "https://www.marxists.org/chinese/abc/index.htm",
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
title: "中文马克思主义文库搜索",
|
|
66
|
+
latinName: "",
|
|
67
|
+
kind: "site-meta",
|
|
68
|
+
path: "search/index.html",
|
|
69
|
+
url: "https://www.marxists.org/chinese/search/index.html",
|
|
70
|
+
},
|
|
71
|
+
]);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("parses work links with section, note, and resource format", () => {
|
|
75
|
+
const rows = parseMarxistsWorks(
|
|
76
|
+
`
|
|
77
|
+
<b><font color="#FF0000" size="5">著 作</font></b>
|
|
78
|
+
<a href="01.htm">共产党宣言</a>(1848年)
|
|
79
|
+
<a href="../pdf/marx/texts/3.pdf">马克思:黑格尔法哲学批判</a>
|
|
80
|
+
`,
|
|
81
|
+
"marx/index.htm",
|
|
82
|
+
"https://www.marxists.org/chinese/marx/index.htm",
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
expect(rows).toEqual([
|
|
86
|
+
{
|
|
87
|
+
scope: "marx/index.htm",
|
|
88
|
+
section: "著 作",
|
|
89
|
+
title: "共产党宣言",
|
|
90
|
+
note: "(1848年)",
|
|
91
|
+
format: "htm",
|
|
92
|
+
path: "marx/01.htm",
|
|
93
|
+
url: "https://www.marxists.org/chinese/marx/01.htm",
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
scope: "marx/index.htm",
|
|
97
|
+
section: "著 作",
|
|
98
|
+
title: "马克思:黑格尔法哲学批判",
|
|
99
|
+
note: "",
|
|
100
|
+
format: "pdf",
|
|
101
|
+
path: "pdf/marx/texts/3.pdf",
|
|
102
|
+
url: "https://www.marxists.org/chinese/pdf/marx/texts/3.pdf",
|
|
103
|
+
},
|
|
104
|
+
]);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("extracts readable article metadata and body text", () => {
|
|
108
|
+
const html = `
|
|
109
|
+
<html>
|
|
110
|
+
<head><title>马克思 恩格斯:共产党宣言(1848年)</title></head>
|
|
111
|
+
<body>
|
|
112
|
+
<p class="title0">共产党宣言</p>
|
|
113
|
+
<p class="author">马克思 恩格斯</p>
|
|
114
|
+
<p class="date">(1848年)</p>
|
|
115
|
+
<script>ignored()</script>
|
|
116
|
+
<h3>一、资产者和无产者</h3>
|
|
117
|
+
&Oslash; 译序<br>
|
|
118
|
+
至今一切社会的历史 都是阶级斗争的历史。<br>
|
|
119
|
+
<a href="#note">注释</a>
|
|
120
|
+
</body>
|
|
121
|
+
</html>
|
|
122
|
+
`;
|
|
123
|
+
|
|
124
|
+
expect(marxistsHtmlToText(html)).toContain(
|
|
125
|
+
"至今一切社会的历史 都是阶级斗争的历史。",
|
|
126
|
+
);
|
|
127
|
+
expect(marxistsHtmlToText(html)).toContain("Ø 译序");
|
|
128
|
+
expect(
|
|
129
|
+
mapMarxistsReadRow(
|
|
130
|
+
html,
|
|
131
|
+
"https://www.marxists.org/chinese/marx/01.htm",
|
|
132
|
+
500,
|
|
133
|
+
),
|
|
134
|
+
).toMatchObject({
|
|
135
|
+
title: "共产党宣言",
|
|
136
|
+
author: "马克思 恩格斯",
|
|
137
|
+
date: "(1848年)",
|
|
138
|
+
url: "https://www.marxists.org/chinese/marx/01.htm",
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("sniffs UTF-8 pages without forcing GB18030", () => {
|
|
143
|
+
const html = '<meta charset="UTF-8">中文马克思主义文库搜索';
|
|
144
|
+
const bytes = new TextEncoder().encode(html);
|
|
145
|
+
expect(decodeMarxistsBuffer(bytes.buffer)).toContain(
|
|
146
|
+
"中文马克思主义文库搜索",
|
|
147
|
+
);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("returns a Western Marxism reading list with directly readable paths", () => {
|
|
151
|
+
const rows = marxistsReadingListRows("western-marxism");
|
|
152
|
+
|
|
153
|
+
expect(rows.map((row) => row.author)).toEqual(
|
|
154
|
+
expect.arrayContaining(["葛兰西", "卢卡奇", "科尔施", "阿尔都塞"]),
|
|
155
|
+
);
|
|
156
|
+
expect(rows).toContainEqual(
|
|
157
|
+
expect.objectContaining({
|
|
158
|
+
author: "卢卡奇",
|
|
159
|
+
title: "《历史与阶级意识》",
|
|
160
|
+
path: "georg-lukacs/1922/index.htm",
|
|
161
|
+
readCommand: "unicli marxists-cn read georg-lukacs/1922/index.htm",
|
|
162
|
+
}),
|
|
163
|
+
);
|
|
164
|
+
expect(
|
|
165
|
+
rows.every((row) =>
|
|
166
|
+
row.url.startsWith("https://www.marxists.org/chinese/"),
|
|
167
|
+
),
|
|
168
|
+
).toBe(true);
|
|
169
|
+
expect(() => marxistsReadingListRows("unknown")).toThrow(
|
|
170
|
+
"reading-list preset",
|
|
171
|
+
);
|
|
172
|
+
});
|
|
173
|
+
});
|