@yukioa2z/visa-apply 3.0.1 → 3.0.3
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 +15 -6
- package/bin/install.js +80 -25
- package/package.json +1 -1
- package/skill/SKILL.md +5 -0
- package/skill/references/policy-monitor.json +3280 -0
- package/skill/scripts/policy_monitor.py +473 -0
package/README.md
CHANGED
|
@@ -5,7 +5,14 @@ Research, prepare, review, and track visa applications with current official sou
|
|
|
5
5
|
[Website](https://yukioa2z.github.io/visa-apply/) · [Source](https://github.com/Yukioa2z/visa-apply)
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
|
-
npx
|
|
8
|
+
npx @yukioa2z/visa-apply
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Run in a terminal and pick your agent when prompted. To skip the prompt, pass your agent's skills directory:
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npx @yukioa2z/visa-apply -- --dest ~/.claude/skills # Claude Code
|
|
15
|
+
npx @yukioa2z/visa-apply -- --dest ~/.codex/skills # Codex
|
|
9
16
|
```
|
|
10
17
|
|
|
11
18
|
Then invoke. To just check whether you need a visa:
|
|
@@ -20,11 +27,7 @@ Many trips end there with a visa-free or ETA answer. To prepare a full applicati
|
|
|
20
27
|
Use $visa-apply to help me prepare a visa application for my destination and visa type.
|
|
21
28
|
```
|
|
22
29
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
```sh
|
|
26
|
-
npx --yes @yukioa2z/visa-apply -- --dest ~/.claude/skills
|
|
27
|
-
```
|
|
30
|
+
`--dest` is your agent's skills root; the installer copies the skill into `<dest>/visa-apply`. Point it at whatever directory your agent scans — Claude Code, Codex, Hermes, OpenClaw, or another agent. Run with `--help` to see the target paths.
|
|
28
31
|
|
|
29
32
|
## Pipeline
|
|
30
33
|
|
|
@@ -44,6 +47,12 @@ No cached source stores a visa-free or visa-required answer. Every case must be
|
|
|
44
47
|
|
|
45
48
|
Government immigration, foreign-ministry, and embassy pages are the rule authority. Delegated visa application centres are used only for appointment and submission logistics.
|
|
46
49
|
|
|
50
|
+
## Weekly source monitoring
|
|
51
|
+
|
|
52
|
+
Every Monday at 00:00 Asia/Shanghai, GitHub Actions compares normalized content fingerprints for every registered official visa source. All 250 destinations appear in the generated monitor: destinations with registered sources receive a change status, while destinations without a source seed are explicitly marked as requiring live official-source discovery.
|
|
53
|
+
|
|
54
|
+
A new fingerprint is first recorded as a review candidate and is only confirmed as changed when the same fingerprint appears in the next run. Either state is a review signal, not a visa-policy verdict. The workflow records the result in `skill/references/policy-monitor.json`, increments the package patch version, commits the report, and dispatches the npm trusted-publishing workflow. This keeps the installable skill current without turning an arbitrary webpage edit into legal guidance.
|
|
55
|
+
|
|
47
56
|
The applicant model is global. It keeps citizenship, travel-document issuer, legal residence, current location, consular application location, and transit route separate, including dual nationals, third-country applicants, minors, and holders of refugee or other non-passport travel documents.
|
|
48
57
|
|
|
49
58
|
This skill is not legal advice. The applicant must review all information and handle applicant-only declarations, signatures, certifications, CAPTCHA, and submission.
|
package/bin/install.js
CHANGED
|
@@ -3,20 +3,32 @@
|
|
|
3
3
|
const fs = require("fs");
|
|
4
4
|
const os = require("os");
|
|
5
5
|
const path = require("path");
|
|
6
|
+
const readline = require("readline");
|
|
6
7
|
|
|
7
8
|
const skillName = "visa-apply";
|
|
8
9
|
const packageRoot = path.resolve(__dirname, "..");
|
|
9
10
|
const sourceDir = path.join(packageRoot, "skill");
|
|
10
11
|
|
|
12
|
+
// Known agents and the skills directory each one scans.
|
|
13
|
+
const AGENTS = [
|
|
14
|
+
{ label: "Claude Code", dir: "~/.claude/skills" },
|
|
15
|
+
{ label: "Codex", dir: "~/.codex/skills" },
|
|
16
|
+
];
|
|
17
|
+
|
|
11
18
|
function usage() {
|
|
19
|
+
const lines = AGENTS.map(
|
|
20
|
+
(a) => ` ${a.label.padEnd(13)} npx @yukioa2z/visa-apply -- --dest ${a.dir}`
|
|
21
|
+
).join("\n");
|
|
12
22
|
console.log(`Install ${skillName}
|
|
13
23
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
npx @yukioa2z/visa-apply -- --dest
|
|
24
|
+
Pick your agent's skills directory with --dest:
|
|
25
|
+
${lines}
|
|
26
|
+
Other agent npx @yukioa2z/visa-apply -- --dest <your agent's skills dir>
|
|
27
|
+
|
|
28
|
+
Run with no --dest in a terminal to choose interactively.
|
|
17
29
|
|
|
18
30
|
Options:
|
|
19
|
-
--dest <path> Skill root directory.
|
|
31
|
+
--dest <path> Skill root directory.
|
|
20
32
|
--dry-run Print the destination without copying files.
|
|
21
33
|
--help Show this help message.
|
|
22
34
|
`);
|
|
@@ -36,32 +48,75 @@ function readOption(name) {
|
|
|
36
48
|
return args[index + 1];
|
|
37
49
|
}
|
|
38
50
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
51
|
+
function install(destRoot, dryRun) {
|
|
52
|
+
const destDir = path.join(destRoot, skillName);
|
|
53
|
+
if (dryRun) {
|
|
54
|
+
console.log(destDir);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
fs.mkdirSync(destRoot, { recursive: true });
|
|
58
|
+
fs.rmSync(destDir, { recursive: true, force: true });
|
|
59
|
+
fs.cpSync(sourceDir, destDir, { recursive: true });
|
|
60
|
+
console.log(`Installed ${skillName} to ${destDir}`);
|
|
61
|
+
console.log(
|
|
62
|
+
`Try: Use $${skillName} to check your visa need and prepare an application dossier.`
|
|
63
|
+
);
|
|
43
64
|
}
|
|
44
65
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
66
|
+
function promptAgent() {
|
|
67
|
+
return new Promise((resolve) => {
|
|
68
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
69
|
+
console.log("Which agent are you installing for?\n");
|
|
70
|
+
AGENTS.forEach((a, i) => console.log(` ${i + 1}) ${a.label} (${a.dir})`));
|
|
71
|
+
console.log(` ${AGENTS.length + 1}) Other (enter a path)\n`);
|
|
72
|
+
rl.question("Choice: ", (answer) => {
|
|
73
|
+
rl.close();
|
|
74
|
+
const n = parseInt(answer.trim(), 10);
|
|
75
|
+
if (n >= 1 && n <= AGENTS.length) {
|
|
76
|
+
resolve(AGENTS[n - 1].dir);
|
|
77
|
+
} else if (n === AGENTS.length + 1) {
|
|
78
|
+
const rl2 = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
79
|
+
rl2.question("Skills directory path: ", (p) => {
|
|
80
|
+
rl2.close();
|
|
81
|
+
resolve(p.trim() || null);
|
|
82
|
+
});
|
|
83
|
+
} else {
|
|
84
|
+
resolve(null);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
});
|
|
48
88
|
}
|
|
49
89
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
90
|
+
async function main() {
|
|
91
|
+
const args = process.argv.slice(2);
|
|
92
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
93
|
+
usage();
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (!fs.existsSync(sourceDir)) {
|
|
97
|
+
console.error(`Skill source not found: ${sourceDir}`);
|
|
98
|
+
process.exitCode = 1;
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
53
101
|
|
|
54
|
-
const
|
|
55
|
-
|
|
102
|
+
const dryRun = args.includes("--dry-run");
|
|
103
|
+
let dest = readOption("--dest");
|
|
56
104
|
|
|
57
|
-
if (
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
105
|
+
if (!dest) {
|
|
106
|
+
// No target given. Ask interactively when attached to a terminal;
|
|
107
|
+
// otherwise (agent/CI) print guidance and exit without guessing.
|
|
108
|
+
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
109
|
+
dest = await promptAgent();
|
|
110
|
+
}
|
|
111
|
+
if (!dest) {
|
|
112
|
+
console.error("No skills directory chosen.\n");
|
|
113
|
+
usage();
|
|
114
|
+
process.exitCode = 1;
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
61
118
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
fs.cpSync(sourceDir, destDir, { recursive: true });
|
|
119
|
+
install(path.resolve(expandHome(dest)), dryRun);
|
|
120
|
+
}
|
|
65
121
|
|
|
66
|
-
|
|
67
|
-
console.log(`Try: Use $${skillName} to check your visa need and prepare an application dossier.`);
|
|
122
|
+
main();
|
package/package.json
CHANGED
package/skill/SKILL.md
CHANGED
|
@@ -23,6 +23,7 @@ This skill is not legal advice. The applicant must review every answer and handl
|
|
|
23
23
|
3. Run the mandatory live visa-need check before detailed intake.
|
|
24
24
|
- Read `references/live-route-check.md`.
|
|
25
25
|
- Resolve the destination in `references/jurisdictions.json`; cached starting sources are in `references/official-sources.json`.
|
|
26
|
+
- Consult `references/policy-monitor.json` when present. A changed fingerprint means the official page needs review; it is never a visa verdict and never replaces the live check.
|
|
26
27
|
- Run `python3 scripts/source_registry.py live-check-plan <country> ...` when useful.
|
|
27
28
|
- Browse current destination-government and responsible-mission sources for the exact passport, residence, purpose, dates, duration, entries, arrival mode, and transit itinerary.
|
|
28
29
|
- Cross-check IATA Travel Centre/Timatic or the operating carrier for boarding requirements. Treat it as operational evidence, not legal authority.
|
|
@@ -42,6 +43,7 @@ This skill is not legal advice. The applicant must review every answer and handl
|
|
|
42
43
|
- No chat note or scratch file may become more authoritative than the HTML.
|
|
43
44
|
8. Run `references/quality-gates.md`, then stop at the applicant review gate before portal entry. Call out inferred values, stale sources, missing documents, expiring evidence, and unresolved conflicts.
|
|
44
45
|
9. Assist with form entry using Browser or Computer Use after review.
|
|
46
|
+
- Before filling anything, make sure the dossier HTML is open in the user's default viewer (open it if it is not) so they can follow progress while you enter the form. Keep updating that file as each field is filled; the user refreshes to see the latest.
|
|
45
47
|
- In non-Codex environments, use the equivalent browser/computer capability, such as Peekaboo or the runtime's supported automation skill.
|
|
46
48
|
- Never bypass CAPTCHA or security controls, invent data, or perform an applicant-only signature/certification.
|
|
47
49
|
10. Backfill application IDs, receipts, appointments/biometrics, document requests, decision status, and passport/visa return details into the HTML.
|
|
@@ -68,6 +70,8 @@ python3 scripts/create_dossier.py /path/to/visa-dossier.html \
|
|
|
68
70
|
--transit "Singapore, airside"
|
|
69
71
|
```
|
|
70
72
|
|
|
73
|
+
Immediately open the dossier in the user's default viewer so they can watch it fill in as the interview proceeds. Use the platform opener: `open <path>` on macOS, `xdg-open <path>` on Linux, `start "" <path>` on Windows. Open it once; each later HTML update lands in the same file, so the user just refreshes the tab. If no opener is available (headless/remote), tell the user the local path to open manually.
|
|
74
|
+
|
|
71
75
|
## References
|
|
72
76
|
|
|
73
77
|
- Full pipeline and source freshness rules: `references/pipeline.md`
|
|
@@ -77,4 +81,5 @@ python3 scripts/create_dossier.py /path/to/visa-dossier.html \
|
|
|
77
81
|
- Submission, document, timing, and privacy gates: `references/quality-gates.md`
|
|
78
82
|
- Searchable destination directory: `references/jurisdictions.json`
|
|
79
83
|
- Official source registry: `references/official-sources.json`
|
|
84
|
+
- Weekly official-source change signals: `references/policy-monitor.json` (source health only, never a visa verdict)
|
|
80
85
|
- Full country adapters: `references/countries/` — United States DS-160 (`us.md`), Schengen Type C (`schengen.md`), Canada IRCC (`ca.md`), United Kingdom (`uk.md`), Australia (`au.md`), Japan (`jp.md`). Every other destination uses a source-seeded or live-discovered adapter.
|