@flytedesk/app-kit 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/dist/bigquery/client.d.ts +18 -0
- package/dist/bigquery/client.js +37 -0
- package/dist/bigquery/client.js.map +1 -0
- package/dist/bigquery/errors.d.ts +26 -0
- package/dist/bigquery/errors.js +80 -0
- package/dist/bigquery/errors.js.map +1 -0
- package/dist/bigquery/extract.d.ts +15 -0
- package/dist/bigquery/extract.js +88 -0
- package/dist/bigquery/extract.js.map +1 -0
- package/dist/bigquery/index.d.ts +47 -0
- package/dist/bigquery/index.js +46 -0
- package/dist/bigquery/index.js.map +1 -0
- package/dist/bigquery/labels.d.ts +16 -0
- package/dist/bigquery/labels.js +26 -0
- package/dist/bigquery/labels.js.map +1 -0
- package/dist/bigquery/query.d.ts +16 -0
- package/dist/bigquery/query.js +86 -0
- package/dist/bigquery/query.js.map +1 -0
- package/dist/bigquery/types.d.ts +155 -0
- package/dist/bigquery/types.js +15 -0
- package/dist/bigquery/types.js.map +1 -0
- package/dist/chat/callback-secret.d.ts +21 -0
- package/dist/chat/callback-secret.js +33 -0
- package/dist/chat/callback-secret.js.map +1 -0
- package/dist/chat/env.d.ts +27 -0
- package/dist/chat/env.js +44 -0
- package/dist/chat/env.js.map +1 -0
- package/dist/chat/index.d.ts +72 -0
- package/dist/chat/index.js +70 -0
- package/dist/chat/index.js.map +1 -0
- package/dist/chat/launcher.d.ts +43 -0
- package/dist/chat/launcher.js +103 -0
- package/dist/chat/launcher.js.map +1 -0
- package/dist/chat/mcp-protocol.d.ts +96 -0
- package/dist/chat/mcp-protocol.js +200 -0
- package/dist/chat/mcp-protocol.js.map +1 -0
- package/dist/chat/mcp-server.d.ts +17 -0
- package/dist/chat/mcp-server.js +71 -0
- package/dist/chat/mcp-server.js.map +1 -0
- package/dist/chat/types.d.ts +91 -0
- package/dist/chat/types.js +5 -0
- package/dist/chat/types.js.map +1 -0
- package/dist/cli/flags-sync.js +2 -5
- package/dist/cli/flags-sync.js.map +1 -1
- package/dist/cli/profile-sync.js +2 -5
- package/dist/cli/profile-sync.js.map +1 -1
- package/dist/cli/sync-engine.d.ts +32 -0
- package/dist/cli/sync-engine.js +190 -23
- package/dist/cli/sync-engine.js.map +1 -1
- package/dist/cli/trace-sync.js +2 -5
- package/dist/cli/trace-sync.js.map +1 -1
- package/package.json +10 -1
- package/scripts/pending-release-count.mjs +37 -0
- package/scripts/release.sh +126 -0
- package/scripts/release.test.ts +205 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { describe, expect, it, beforeAll } from "vitest";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join, resolve } from "node:path";
|
|
6
|
+
|
|
7
|
+
// scripts/release.sh refuses to do anything except from the sanctioned
|
|
8
|
+
// deploy clone, with a clean tree, without a live lock, and only for a
|
|
9
|
+
// commit reachable from origin/main. Those guards run before npm ci / the
|
|
10
|
+
// gates, so they're cheap and fully testable against throwaway git repos
|
|
11
|
+
// (no Docker, no network, no real npm publish).
|
|
12
|
+
|
|
13
|
+
const SCRIPT_PATH = resolve(__dirname, "release.sh");
|
|
14
|
+
|
|
15
|
+
// On Windows, a bare `bash` on PATH can resolve to the WSL launcher in
|
|
16
|
+
// System32 instead of Git Bash, which can't reliably run against a
|
|
17
|
+
// C:/Users/... working tree. Find Git Bash explicitly when it exists;
|
|
18
|
+
// fall back to `bash` (e.g. on Linux CI, where `bash` is unambiguous).
|
|
19
|
+
function resolveBash(): string {
|
|
20
|
+
const candidates = [
|
|
21
|
+
"C:\\Program Files\\Git\\bin\\bash.exe",
|
|
22
|
+
"C:\\Program Files\\Git\\usr\\bin\\bash.exe",
|
|
23
|
+
];
|
|
24
|
+
for (const c of candidates) {
|
|
25
|
+
if (existsSync(c)) return c;
|
|
26
|
+
}
|
|
27
|
+
return "bash";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const BASH = resolveBash();
|
|
31
|
+
|
|
32
|
+
function run(cwd: string, args: string[] = []) {
|
|
33
|
+
const result = spawnSync(BASH, [SCRIPT_PATH, ...args], {
|
|
34
|
+
cwd,
|
|
35
|
+
encoding: "utf8",
|
|
36
|
+
env: { ...process.env },
|
|
37
|
+
});
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function git(cwd: string, args: string[]) {
|
|
42
|
+
const result = spawnSync("git", args, { cwd, encoding: "utf8" });
|
|
43
|
+
if (result.status !== 0) {
|
|
44
|
+
throw new Error(
|
|
45
|
+
`git ${args.join(" ")} failed in ${cwd}: ${result.stderr}${result.stdout}`,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
return result.stdout;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function initRepoWithCommit(dir: string) {
|
|
52
|
+
git(dir, ["init", "-q", "-b", "main"]);
|
|
53
|
+
git(dir, ["config", "user.email", "test@example.com"]);
|
|
54
|
+
git(dir, ["config", "user.name", "Test"]);
|
|
55
|
+
// Ignore the script's own local-only marker/lock files so creating them
|
|
56
|
+
// doesn't itself count as "dirty" in these throwaway repos.
|
|
57
|
+
writeFileSync(join(dir, ".gitignore"), ".deploy-clone-marker\n.release.lock\n");
|
|
58
|
+
writeFileSync(join(dir, "README.md"), "test repo\n");
|
|
59
|
+
git(dir, ["add", "."]);
|
|
60
|
+
git(dir, ["commit", "-q", "-m", "initial commit"]);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function addMarker(dir: string) {
|
|
64
|
+
writeFileSync(join(dir, ".deploy-clone-marker"), "test marker\n");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
describe("scripts/release.sh guards", () => {
|
|
68
|
+
let workDir: string;
|
|
69
|
+
|
|
70
|
+
beforeAll(() => {
|
|
71
|
+
workDir = mkdtempSync(join(tmpdir(), "release-sh-test-"));
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("refuses to run outside the deploy clone (no marker file)", () => {
|
|
75
|
+
const dir = mkdtempSync(join(workDir, "no-marker-"));
|
|
76
|
+
initRepoWithCommit(dir);
|
|
77
|
+
// deliberately no .deploy-clone-marker
|
|
78
|
+
|
|
79
|
+
const result = run(dir);
|
|
80
|
+
|
|
81
|
+
expect(result.status).not.toBe(0);
|
|
82
|
+
expect(result.stderr).toMatch(/not the sanctioned deploy clone/i);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("refuses a dirty working tree even with the marker present", () => {
|
|
86
|
+
const dir = mkdtempSync(join(workDir, "dirty-"));
|
|
87
|
+
initRepoWithCommit(dir);
|
|
88
|
+
addMarker(dir);
|
|
89
|
+
// Make an uncommitted, non-ignored change.
|
|
90
|
+
writeFileSync(join(dir, "README.md"), "modified, uncommitted\n");
|
|
91
|
+
|
|
92
|
+
const result = run(dir);
|
|
93
|
+
|
|
94
|
+
expect(result.status).not.toBe(0);
|
|
95
|
+
expect(result.stderr).toMatch(/dirty/i);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("refuses to run when the lock file is already held", () => {
|
|
99
|
+
const dir = mkdtempSync(join(workDir, "locked-"));
|
|
100
|
+
initRepoWithCommit(dir);
|
|
101
|
+
addMarker(dir);
|
|
102
|
+
writeFileSync(join(dir, ".release.lock"), "99999\n");
|
|
103
|
+
|
|
104
|
+
const result = run(dir);
|
|
105
|
+
|
|
106
|
+
expect(result.status).not.toBe(0);
|
|
107
|
+
expect(result.stderr).toMatch(/lock file .* already exists/i);
|
|
108
|
+
// The guard must not have deleted a lock file it didn't create itself
|
|
109
|
+
// (the trap only fires once *this* run successfully takes the lock).
|
|
110
|
+
expect(existsSync(join(dir, ".release.lock"))).toBe(true);
|
|
111
|
+
rmSync(join(dir, ".release.lock"));
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("refuses a target commit that is not reachable from origin/main", () => {
|
|
115
|
+
// A bare "origin" with just the initial commit on main.
|
|
116
|
+
const originDir = mkdtempSync(join(workDir, "origin-"));
|
|
117
|
+
git(originDir, ["init", "-q", "--bare", "-b", "main"]);
|
|
118
|
+
|
|
119
|
+
const seedDir = mkdtempSync(join(workDir, "seed-"));
|
|
120
|
+
initRepoWithCommit(seedDir);
|
|
121
|
+
git(seedDir, ["remote", "add", "origin", originDir]);
|
|
122
|
+
git(seedDir, ["push", "-q", "origin", "main"]);
|
|
123
|
+
|
|
124
|
+
// The deploy clone: clone of origin, plus a local commit on a throwaway
|
|
125
|
+
// branch that is never pushed, so it is not an ancestor of origin/main.
|
|
126
|
+
// main itself stays exactly at origin/main's tip, so the tree the
|
|
127
|
+
// guards see is clean.
|
|
128
|
+
const cloneDir = join(workDir, "clone-unreachable");
|
|
129
|
+
git(workDir, ["clone", "-q", originDir, cloneDir]);
|
|
130
|
+
addMarker(cloneDir);
|
|
131
|
+
git(cloneDir, ["checkout", "-q", "-b", "throwaway"]);
|
|
132
|
+
writeFileSync(join(cloneDir, "unmerged.txt"), "local-only change\n");
|
|
133
|
+
git(cloneDir, ["add", "unmerged.txt"]);
|
|
134
|
+
git(cloneDir, ["commit", "-q", "-m", "unmerged local commit"]);
|
|
135
|
+
const unmergedSha = git(cloneDir, ["rev-parse", "HEAD"]).trim();
|
|
136
|
+
git(cloneDir, ["checkout", "-q", "main"]);
|
|
137
|
+
|
|
138
|
+
const result = run(cloneDir, [unmergedSha]);
|
|
139
|
+
|
|
140
|
+
expect(result.status).not.toBe(0);
|
|
141
|
+
expect(result.stderr).toMatch(/not reachable from origin\/main/i);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// scripts/pending-release-count.mjs decides "version + publish" vs "no-op".
|
|
146
|
+
// A release runs from a clone of main, so pending changesets are already on
|
|
147
|
+
// origin/main. The first real release (AK-13, 2026-09-24) counted zero because
|
|
148
|
+
// it asked `changeset status --since=origin/main`; these tests pin the fix by
|
|
149
|
+
// reproducing that exact shape: changesets committed AND pushed.
|
|
150
|
+
describe("scripts/pending-release-count.mjs", () => {
|
|
151
|
+
const COUNT_SCRIPT = resolve(__dirname, "pending-release-count.mjs");
|
|
152
|
+
let workDir: string;
|
|
153
|
+
|
|
154
|
+
beforeAll(() => {
|
|
155
|
+
workDir = mkdtempSync(join(tmpdir(), "pending-count-test-"));
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
function cloneOfPushedPackage(name: string, changesets: Record<string, string>) {
|
|
159
|
+
const originDir = mkdtempSync(join(workDir, `${name}-origin-`));
|
|
160
|
+
git(originDir, ["init", "-q", "--bare", "-b", "main"]);
|
|
161
|
+
|
|
162
|
+
const seedDir = mkdtempSync(join(workDir, `${name}-seed-`));
|
|
163
|
+
initRepoWithCommit(seedDir);
|
|
164
|
+
writeFileSync(
|
|
165
|
+
join(seedDir, "package.json"),
|
|
166
|
+
JSON.stringify({ name: "@test/pkg", version: "0.3.2" }, null, 2),
|
|
167
|
+
);
|
|
168
|
+
mkdirSync(join(seedDir, ".changeset"));
|
|
169
|
+
writeFileSync(
|
|
170
|
+
join(seedDir, ".changeset", "config.json"),
|
|
171
|
+
JSON.stringify({ changelog: false, commit: false, baseBranch: "main", access: "public" }),
|
|
172
|
+
);
|
|
173
|
+
for (const [file, body] of Object.entries(changesets)) {
|
|
174
|
+
writeFileSync(join(seedDir, ".changeset", file), body);
|
|
175
|
+
}
|
|
176
|
+
git(seedDir, ["add", "."]);
|
|
177
|
+
git(seedDir, ["commit", "-q", "-m", "package with changesets"]);
|
|
178
|
+
git(seedDir, ["remote", "add", "origin", originDir]);
|
|
179
|
+
git(seedDir, ["push", "-q", "origin", "main"]);
|
|
180
|
+
|
|
181
|
+
const cloneDir = join(workDir, `${name}-clone`);
|
|
182
|
+
git(workDir, ["clone", "-q", originDir, cloneDir]);
|
|
183
|
+
return cloneDir;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function count(cwd: string) {
|
|
187
|
+
const result = spawnSync(process.execPath, [COUNT_SCRIPT], { cwd, encoding: "utf8" });
|
|
188
|
+
if (result.status !== 0) throw new Error(result.stderr || result.stdout);
|
|
189
|
+
return result.stdout;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
it("counts changesets that are already on origin/main", () => {
|
|
193
|
+
const clone = cloneOfPushedPackage("pending", {
|
|
194
|
+
"minor-feature.md": '---\n"@test/pkg": minor\n---\n\nA feature.\n',
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
expect(count(clone)).toBe("1");
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it("reports zero when no changesets are pending", () => {
|
|
201
|
+
const clone = cloneOfPushedPackage("none", {});
|
|
202
|
+
|
|
203
|
+
expect(count(clone)).toBe("0");
|
|
204
|
+
});
|
|
205
|
+
});
|