@kendoo.agentdesk/agentdesk 0.19.5 → 0.19.6
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/CHANGELOG.md +5 -0
- package/cli/bootstrap.mjs +37 -24
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -13,6 +13,11 @@ Internal refactors, infrastructure changes, and architectural notes are not list
|
|
|
13
13
|
### Added
|
|
14
14
|
- `[UI]` Private-session sharing flow. When someone visits a session URL they don't own, they now see a friendly "Shh… this one's private" page with a one-click "Request access" button instead of a blank error. The session owner sees pending requests in a new header inbox and can grant viewer access for just that session or the whole project. Viewer-granted sessions show up in the teammate's sidebar tagged as a viewer.
|
|
15
15
|
|
|
16
|
+
## [0.19.6] — 2026-04-19
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- `[CLI]` `agentdesk bootstrap` now auto-selects the project silently when the git remote's repo name matches the project's id or name (case-insensitive, scope-stripped), in addition to the existing exact `github.repo` match. No confirmation prompt is shown for a confident single match — the clone just picks up the right project and continues. The numbered picker is only shown when auto-match finds zero or multiple candidates.
|
|
20
|
+
|
|
16
21
|
## [0.19.5] — 2026-04-19
|
|
17
22
|
|
|
18
23
|
### Changed
|
package/cli/bootstrap.mjs
CHANGED
|
@@ -57,15 +57,20 @@ async function fetchProjectSettings(apiKey, projectId) {
|
|
|
57
57
|
} catch { return {}; }
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
// Normalize a name for fuzzy comparison: lowercase, strip npm scope (@scope/)
|
|
61
|
+
// and everything up to the last `/`, then drop non-alphanumerics.
|
|
62
|
+
function normalizeName(s) {
|
|
63
|
+
if (!s) return "";
|
|
64
|
+
const tail = s.includes("/") ? s.slice(s.lastIndexOf("/") + 1) : s;
|
|
65
|
+
return tail.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
66
|
+
}
|
|
67
|
+
|
|
60
68
|
// Discover the server-side project for this clone when .agentdesk.json is
|
|
61
|
-
// absent. Strategy:
|
|
62
|
-
// 1.
|
|
63
|
-
// 2
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
// 4. Otherwise show a numbered picker of all the user's projects.
|
|
67
|
-
// 5. Write a minimal `.agentdesk.json` locally so loadConfig takes over
|
|
68
|
-
// from here.
|
|
69
|
+
// absent. Strategy (each tier that yields exactly one match auto-selects):
|
|
70
|
+
// Tier 1 — server-side github.repo equals the local git remote (owner/repo).
|
|
71
|
+
// Tier 2 — the repo name from the remote matches the project id or name
|
|
72
|
+
// (case-insensitive, scope-stripped).
|
|
73
|
+
// When 0 or 2+ projects match, fall back to a numbered picker.
|
|
69
74
|
// Returns the chosen projectKey, or null if the user aborts.
|
|
70
75
|
async function discoverProject(rl, cwd, apiKey) {
|
|
71
76
|
const remote = detectGitRemote(cwd);
|
|
@@ -83,35 +88,44 @@ async function discoverProject(rl, cwd, apiKey) {
|
|
|
83
88
|
|
|
84
89
|
// Fetch settings in parallel so we can display/match the configured repo.
|
|
85
90
|
const settings = await Promise.all(projects.map(p => fetchProjectSettings(apiKey, p.id)));
|
|
91
|
+
const remoteRepoName = remote ? remote.split("/").pop() : null;
|
|
92
|
+
const remoteKey = normalizeName(remoteRepoName);
|
|
86
93
|
const rows = projects.map((p, i) => {
|
|
87
94
|
const repo = settings[i]?.github?.repo || null;
|
|
88
|
-
const
|
|
89
|
-
|
|
95
|
+
const tier1 = remote && repo && repo.toLowerCase() === remote.toLowerCase();
|
|
96
|
+
const tier2 = !tier1 && remoteKey && (
|
|
97
|
+
normalizeName(p.id) === remoteKey || normalizeName(p.name) === remoteKey
|
|
98
|
+
);
|
|
99
|
+
return { project: p, settings: settings[i] || {}, repo, tier1, tier2 };
|
|
90
100
|
});
|
|
91
101
|
|
|
92
|
-
const
|
|
102
|
+
const tier1Matches = rows.filter(r => r.tier1);
|
|
103
|
+
const tier2Matches = rows.filter(r => r.tier2);
|
|
93
104
|
let chosen = null;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
105
|
+
let matchReason = null;
|
|
106
|
+
|
|
107
|
+
if (tier1Matches.length === 1) {
|
|
108
|
+
chosen = tier1Matches[0];
|
|
109
|
+
matchReason = `github.repo matches ${chosen.repo}`;
|
|
110
|
+
} else if (tier1Matches.length === 0 && tier2Matches.length === 1) {
|
|
111
|
+
chosen = tier2Matches[0];
|
|
112
|
+
matchReason = `project name matches repo "${remoteRepoName}"`;
|
|
101
113
|
}
|
|
102
114
|
|
|
103
|
-
if (
|
|
115
|
+
if (chosen) {
|
|
116
|
+
console.log(` ✓ Auto-matched: ${chosen.project.name} (${chosen.project.id}) — ${matchReason}`);
|
|
117
|
+
} else {
|
|
104
118
|
console.log("");
|
|
105
|
-
console.log("
|
|
119
|
+
console.log(" Couldn't auto-match this clone to one of your projects.");
|
|
106
120
|
console.log("");
|
|
107
121
|
rows.forEach((r, i) => {
|
|
108
|
-
const tag = r.
|
|
122
|
+
const tag = r.tier1 ? " ← repo match" : r.tier2 ? " ← name match" : "";
|
|
109
123
|
const repoStr = r.repo ? ` [${r.repo}]` : "";
|
|
110
124
|
console.log(` ${i + 1}) ${r.project.name} (${r.project.id})${repoStr}${tag}`);
|
|
111
125
|
});
|
|
112
126
|
console.log("");
|
|
113
127
|
while (true) {
|
|
114
|
-
const answer = await askInline(rl, `
|
|
128
|
+
const answer = await askInline(rl, ` Pick one (1-${rows.length}, or 'c' to cancel): `);
|
|
115
129
|
const trimmed = answer.trim().toLowerCase();
|
|
116
130
|
if (trimmed === "c" || trimmed === "cancel") return null;
|
|
117
131
|
const num = parseInt(trimmed, 10);
|
|
@@ -124,9 +138,8 @@ async function discoverProject(rl, cwd, apiKey) {
|
|
|
124
138
|
// into it on the next call, producing the full cached view.
|
|
125
139
|
const minimal = { projectKey: chosen.project.id };
|
|
126
140
|
writeFileSync(join(cwd, ".agentdesk.json"), JSON.stringify(minimal, null, 2) + "\n");
|
|
127
|
-
console.log("");
|
|
128
141
|
console.log(` ✓ Wrote .agentdesk.json (projectKey: ${chosen.project.id})`);
|
|
129
|
-
console.log(" (commit this file so future clones skip
|
|
142
|
+
console.log(" (commit this file so future clones skip discovery)");
|
|
130
143
|
return chosen.project.id;
|
|
131
144
|
}
|
|
132
145
|
|