rigjs 4.0.18 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
- import CICD from '@/classes/cicd/CICD';
1
+ import CICD, { DeployTarget } from '@/classes/cicd/CICD';
2
2
  import CICDCmd from '@/classes/cicd/CICDCmd';
3
3
  import CDN from '@/classes/cicd/Deploy/CDN';
4
+ import ESA from '@/classes/cicd/Deploy/ESA';
4
5
 
5
6
  const delay = async (ms: number) => {
6
7
  await new Promise((resolve) => {
@@ -69,6 +70,76 @@ const refreshCache = async (urls: string[], cdn: CDN) => {
69
70
  console.log('RefreshCache Done');
70
71
  };
71
72
 
73
+ /**
74
+ * ESA publish path (edge_provider === 'esa'). Sets back-to-origin URI rewrite
75
+ * rules per domain, then purges the entry URLs.
76
+ *
77
+ * Mapping vs CDN: hash mode only needs the entry page rewritten to
78
+ * `/<deployDir>/index.html` (publicPath already carries deployDir so static
79
+ * files resolve at the OSS origin directly). history/mpa additionally prepend
80
+ * deployDir for static files and fall back to the entry for extension-less
81
+ * routes — those dynamic-rewrite expressions need validation on a live ESA site.
82
+ */
83
+ const publishViaEsa = async (
84
+ cicd: CICD,
85
+ cicdCmd: CICDCmd,
86
+ target: DeployTarget
87
+ ) => {
88
+ const esa = new ESA(target);
89
+ if (!cicdCmd.endpoints || cicdCmd.endpoints.length === 0) {
90
+ throw new Error('Endpoints.length Can Not Be 0!');
91
+ }
92
+ const purgeByDomain: { [domain: string]: string[] } = {};
93
+ for (const endpoint of cicdCmd.endpoints) {
94
+ const deployDir = endpoint.deployDir.replace(/\\/g, '/');
95
+ const webEntryPath = endpoint.web_entry_path || target.web_entry_path || '/';
96
+ const ruleBase = `rig-${deployDir.replace(/[^\w]+/g, '-')}`.replace(
97
+ /-+/g,
98
+ '-'
99
+ );
100
+ for (const domain of endpoint.domains) {
101
+ if (cicd.web_type === 'hash') {
102
+ await esa.setRewriteRule(
103
+ domain,
104
+ `${ruleBase}-entry`,
105
+ `(http.request.uri.path eq "${webEntryPath}")`,
106
+ 'static',
107
+ `/${deployDir}/index.html`,
108
+ 1
109
+ );
110
+ } else {
111
+ await esa.setRewriteRule(
112
+ domain,
113
+ `${ruleBase}-file`,
114
+ `(http.request.uri.path.extension ne "")`,
115
+ 'dynamic',
116
+ `concat("/${deployDir}", http.request.uri.path)`,
117
+ 1
118
+ );
119
+ await esa.setRewriteRule(
120
+ domain,
121
+ `${ruleBase}-entry`,
122
+ 'true',
123
+ cicd.web_type === 'mpa' ? 'dynamic' : 'static',
124
+ cicd.web_type === 'mpa'
125
+ ? `concat("/${deployDir}", http.request.uri.path, ".html")`
126
+ : `/${deployDir}/index.html`,
127
+ 2
128
+ );
129
+ }
130
+ if (!purgeByDomain[domain]) {
131
+ purgeByDomain[domain] = [];
132
+ }
133
+ purgeByDomain[domain].push(`https://${domain}${webEntryPath}`);
134
+ }
135
+ }
136
+ for (const domain of Object.keys(purgeByDomain)) {
137
+ console.log(`ESA purge ${domain}:`, purgeByDomain[domain]);
138
+ await esa.purgeCache(domain, purgeByDomain[domain]);
139
+ }
140
+ console.log('ESA rewrite rules + purge done');
141
+ };
142
+
72
143
  export default async (cmd: any) => {
73
144
  try {
74
145
  const rewriteConfigs: {
@@ -99,6 +170,12 @@ export default async (cmd: any) => {
99
170
  ? cicdCmd.cicd.target[0]
100
171
  : cicdCmd.cicd.target;
101
172
 
173
+ if (target.edge_provider === 'esa') {
174
+ await publishViaEsa(cicd, cicdCmd, target);
175
+ console.log('Publish Done-----');
176
+ return;
177
+ }
178
+
102
179
  const cdn = new CDN(target);
103
180
  const urls: string[] = [];
104
181
  if (!cicdCmd.endpoints || cicdCmd.endpoints.length === 0) {
package/lib/wiki/lint.ts CHANGED
@@ -42,6 +42,7 @@ interface Findings {
42
42
  const REQUIRED_KEYS = ['type', 'sources', 'ingested-at', 'last-updated'] as const;
43
43
  const SOURCE_EXTRA_KEYS = ['source-sha', 'source-path'] as const;
44
44
  const WIKI_SUBDIRS = ['sources', 'entities', 'concepts', 'synthesis', 'queries'] as const;
45
+ const TOP_LEVEL_WIKILINK_TARGETS = ['index', 'overview', 'log', 'reviews', 'purpose', 'schema'] as const;
45
46
 
46
47
  export default async function wikiLint(opts: LintOpts): Promise<void> {
47
48
  const target = requireVault();
@@ -89,6 +90,10 @@ function lintOne(wiki: WikiEntry): Findings {
89
90
  }
90
91
 
91
92
  const slugToRel = new Map<string, string>();
93
+ for (const slug of TOP_LEVEL_WIKILINK_TARGETS) {
94
+ const rel = `${slug}.md`;
95
+ if (fs.existsSync(path.join(wiki.path, rel))) slugToRel.set(slug, rel);
96
+ }
92
97
  for (const p of pages) slugToRel.set(p.slug, p.rel);
93
98
 
94
99
  const linkedSlugs = new Set<string>();
@@ -103,7 +108,7 @@ function lintOne(wiki: WikiEntry): Findings {
103
108
  }
104
109
  const sourcePath = String(p.frontmatter['source-path'] || '');
105
110
  if (sourcePath) {
106
- const abs = path.isAbsolute(sourcePath) ? sourcePath : path.resolve(wiki.path, sourcePath);
111
+ const abs = resolveSourcePath(wiki, sourcePath);
107
112
  if (!fs.existsSync(abs)) {
108
113
  f.missingRawSource.push({ rel: p.rel, sourcePath });
109
114
  } else {
@@ -188,6 +193,23 @@ function extractWikilinks(body: string): string[] {
188
193
  return out;
189
194
  }
190
195
 
196
+ function resolveSourcePath(wiki: WikiEntry, sourcePath: string): string {
197
+ const obsidian = parseObsidianFilePath(sourcePath);
198
+ if (obsidian) return path.resolve(path.dirname(wiki.path), obsidian);
199
+ return path.isAbsolute(sourcePath) ? sourcePath : path.resolve(wiki.path, sourcePath);
200
+ }
201
+
202
+ function parseObsidianFilePath(sourcePath: string): string | null {
203
+ if (!sourcePath.startsWith('obsidian://open?')) return null;
204
+ try {
205
+ const url = new URL(sourcePath);
206
+ const file = url.searchParams.get('file');
207
+ return file && file.trim() ? file : null;
208
+ } catch {
209
+ return null;
210
+ }
211
+ }
212
+
191
213
  function sha256(file: string): string {
192
214
  return crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
193
215
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "rigjs",
3
- "version": "4.0.18",
4
- "versionCode": 26052501,
3
+ "version": "4.1.0",
4
+ "versionCode": 26053101,
5
5
  "description": "A multi-repos dev tool based on yarn and git.Rigjs is intended to be the simplest way to develop,share and deliver codes between different developers or different projects.",
6
6
  "keywords": [
7
7
  "modular",
@@ -36,9 +36,13 @@
36
36
  "doc",
37
37
  "scripts",
38
38
  ".claude/skills/rig-wiki",
39
+ ".claude/skills/rig-package",
40
+ ".claude/skills/rig-cicd",
39
41
  ".claude-plugin",
40
42
  "RIG_WIKI_SKILL.md",
41
43
  "RIG_CREW_SKILL.md",
44
+ "RIG_PACKAGE_SKILL.md",
45
+ "RIG_CICD_SKILL.md",
42
46
  "skills.md",
43
47
  "index.js",
44
48
  "README.md",
@@ -56,13 +60,17 @@
56
60
  "t": "node lib/rig/index.js tag",
57
61
  "deliver": "node scripts/publish.mjs",
58
62
  "deliver:alpha": "rig tag && yarn build && node scripts/publish.mjs --tag alpha",
59
- "build": "esbuild lib/rig/index.ts --platform=node --bundle --sourcemap=inline --minify --outfile=built/index.js --external:shelljs --external:better-sqlite3 --external:bindings --external:proxy-agent --external:@tobilu/qmd",
63
+ "build": "esbuild lib/rig/index.ts --platform=node --bundle --sourcemap=inline --minify --outfile=built/index.js --external:shelljs --external:better-sqlite3 --external:bindings --external:proxy-agent --external:@tobilu/qmd && yarn scan:built",
64
+ "scan:built": "GOMAXPROCS=2 gitleaks detect --source built --no-git --no-banner --redact --exit-code 1",
60
65
  "version:code": "node scripts/version-code.mjs",
61
66
  "version:code:peek": "node scripts/version-code.mjs --peek",
62
67
  "prepublishOnly": "node scripts/version-code.mjs && node scripts/sync-skill.mjs && yarn build",
63
68
  "postinstall": "node scripts/postinstall.mjs"
64
69
  },
65
70
  "dependencies": {
71
+ "@alicloud/esa20240910": "^3.1.2",
72
+ "@alicloud/openapi-client": "^0.4.15",
73
+ "@alicloud/tea-util": "^1.4.11",
66
74
  "@tobilu/qmd": "~2.5.2",
67
75
  "@types/ali-oss": "^6.16.3",
68
76
  "@types/json5": "^2.2.0",
@@ -14,6 +14,8 @@ const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'
14
14
 
15
15
  const skills = [
16
16
  ['RIG_WIKI_SKILL.md', '.claude/skills/rig-wiki/SKILL.md'],
17
+ ['RIG_PACKAGE_SKILL.md', '.claude/skills/rig-package/SKILL.md'],
18
+ ['RIG_CICD_SKILL.md', '.claude/skills/rig-cicd/SKILL.md'],
17
19
  ];
18
20
 
19
21
  for (const [srcRel, destRel] of skills) {
package/skills.md CHANGED
@@ -8,6 +8,8 @@ This page is the skill index for the `rigjs` package. The root `README.md` keeps
8
8
  |---|---|---|---|---|
9
9
  | `rig-wiki` | [`RIG_WIKI_SKILL.md`](./RIG_WIKI_SKILL.md) | [`.claude/skills/rig-wiki/SKILL.md`](./.claude/skills/rig-wiki/SKILL.md) | `rig wiki *` | Karpathy-style LLM wiki operations: scan, fetch, ingest, query, lint, rebuild. |
10
10
  | `rig-crew` | [`RIG_CREW_SKILL.md`](./RIG_CREW_SKILL.md) | (none — vault-level guidance) | `rig crew *` | File-backed, Leader-first multi-agent coordination over an Obsidian vault. |
11
+ | `rig-package` | [`RIG_PACKAGE_SKILL.md`](./RIG_PACKAGE_SKILL.md) | [`.claude/skills/rig-package/SKILL.md`](./.claude/skills/rig-package/SKILL.md) | `rig init` / `install` / `add` / `dev` / `tag` | Git-tag + ssh package manager that replaces a private npm registry; documents every `package.rig.json5#dependencies` field. |
12
+ | `rig-cicd` | [`RIG_CICD_SKILL.md`](./RIG_CICD_SKILL.md) | [`.claude/skills/rig-cicd/SKILL.md`](./.claude/skills/rig-cicd/SKILL.md) | `rig build` / `deploy` / `publish` | Aliyun OSS + CDN static-site CI/CD; one bucket → many sites via CDN URI rewrites set during `rig publish`. Supports hash, history, mpa, pre-built HTML dirs. |
11
13
 
12
14
  `rig-crew` is intentionally not copied into the rigjs package's own `.claude/skills/`. Its instructions belong at the Vault level (the project that uses crew), not at the tool level (rigjs itself).
13
15
 
@@ -89,6 +91,8 @@ Canonical skill files live at the package root:
89
91
 
90
92
  - [`RIG_WIKI_SKILL.md`](./RIG_WIKI_SKILL.md)
91
93
  - [`RIG_CREW_SKILL.md`](./RIG_CREW_SKILL.md)
94
+ - [`RIG_PACKAGE_SKILL.md`](./RIG_PACKAGE_SKILL.md)
95
+ - [`RIG_CICD_SKILL.md`](./RIG_CICD_SKILL.md)
92
96
 
93
97
  A package-internal mirror lives under `.claude/skills/` so the rig package itself (when checked out by another agent) can read its own skills:
94
98
 
@@ -96,7 +100,7 @@ A package-internal mirror lives under `.claude/skills/` so the rig package itsel
96
100
  node scripts/sync-skill.mjs
97
101
  ```
98
102
 
99
- `prepublishOnly` runs the sync script before packaging. Today this plugin-copy set only includes `rig-wiki`; `rig-crew` remains Vault-level guidance and has no in-package `.claude/skills/` copy.
103
+ `prepublishOnly` runs the sync script before packaging. The plugin-copy set covers `rig-wiki`, `rig-package`, and `rig-cicd`; `rig-crew` remains Vault-level guidance and has no in-package `.claude/skills/` copy.
100
104
 
101
105
  ## Documentation Policy
102
106
 
@@ -1,43 +0,0 @@
1
- import { maskSecret, redactTarget, redactCdnUrl } from '@/utils/redact';
2
-
3
- test('maskSecret keeps a head+tail hint for long secrets', () => {
4
- const ak = 'LTAI5t9GjXQc7itTohf68ZLq';
5
- const masked = maskSecret(ak);
6
- expect(masked).not.toContain('GjXQc7it'); // no middle bytes
7
- expect(masked.startsWith('LTAI')).toBe(true);
8
- expect(masked.endsWith('8ZLq')).toBe(true);
9
- });
10
-
11
- test('maskSecret returns plain mask for short / empty input', () => {
12
- expect(maskSecret('')).toBe('');
13
- expect(maskSecret(undefined)).toBe('');
14
- expect(maskSecret('abc')).toBe('****');
15
- expect(maskSecret('abcdefgh')).toBe('****');
16
- });
17
-
18
- test('redactTarget masks access_key / access_secret only', () => {
19
- const out = redactTarget({
20
- id: 'alicloud',
21
- type: 'alicloud',
22
- bucket: 'my-bucket',
23
- region: 'oss-ap-southeast-1',
24
- access_key: 'LTAI5t9GjXQc7itTohf68ZLq',
25
- access_secret: '8jfykQQoK66RldfSo9YlfdLh423GXA',
26
- root_path: '/',
27
- });
28
- expect(out.bucket).toBe('my-bucket');
29
- expect(out.region).toBe('oss-ap-southeast-1');
30
- expect(out.root_path).toBe('/');
31
- expect(out.access_key).not.toContain('GjXQc7it');
32
- expect(out.access_secret).not.toContain('QQoK66Rld');
33
- });
34
-
35
- test('redactCdnUrl masks AccessKeyId and Signature only', () => {
36
- const url =
37
- 'http://cdn.ap-southeast-1.aliyuncs.com?AccessKeyId=LTAI5t9GjXQc7itTohf68ZLq&Action=BatchSetCdnDomainConfig&Signature=iUppVaZSIecVi3DhZZeBCf24Ag0%3D&Timestamp=2026-05-25T08%3A40%3A51.135Z';
38
- const masked = redactCdnUrl(url);
39
- expect(masked).not.toContain('LTAI5t9GjXQc7itTohf68ZLq');
40
- expect(masked).not.toContain('iUppVaZSIecVi3DhZZeBCf24Ag0');
41
- expect(masked).toContain('Action=BatchSetCdnDomainConfig');
42
- expect(masked).toContain('Timestamp=2026-05-25');
43
- });