@topolo/cli 0.6.10 → 0.7.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/dist/index.js +206 -169
- package/package.json +2 -2
- package/skills/codex/AGENTS.md +2 -2
package/dist/index.js
CHANGED
|
@@ -110,57 +110,8 @@ var TopoloHttpError = class extends TopoloSdkError {
|
|
|
110
110
|
}
|
|
111
111
|
};
|
|
112
112
|
var APP_API_URLS = {
|
|
113
|
-
agent: "https://agent.topolo.app",
|
|
114
113
|
auth: "https://auth.topolo.app",
|
|
115
|
-
|
|
116
|
-
blog: "https://blog.topolo.app",
|
|
117
|
-
books: "https://books.topolo.app",
|
|
118
|
-
brand: "https://brand.topolo.app",
|
|
119
|
-
bugfix: "https://bugfix.topolo.app",
|
|
120
|
-
bytes: "https://bytes.topolo.app",
|
|
121
|
-
calendar: "https://calendar.topolo.app",
|
|
122
|
-
campaigns: "https://campaigns.topolo.app",
|
|
123
|
-
capacity: "https://capacity.topolo.app",
|
|
124
|
-
chat: "https://chat.topolo.app",
|
|
125
|
-
commerce: "https://commerce.topolo.app",
|
|
126
|
-
compose: "https://compose.topolo.app",
|
|
127
|
-
consent: "https://consent.topolo.app",
|
|
128
|
-
crm: "https://crm.topolo.app",
|
|
129
|
-
design: "https://design.topolo.app",
|
|
130
|
-
developers: "https://developers.topolo.app",
|
|
131
|
-
director: "https://director.topolo.app",
|
|
132
|
-
feed: "https://feed.topolo.app",
|
|
133
|
-
flow: "https://flow.topolo.app",
|
|
134
|
-
forecast: "https://forecast.topolo.app",
|
|
135
|
-
forms: "https://forms.topolo.app",
|
|
136
|
-
home: "https://home.topolo.app",
|
|
137
|
-
insights: "https://insights.topolo.app",
|
|
138
|
-
inventory: "https://inventory.topolo.app",
|
|
139
|
-
learn: "https://learn.topolo.app",
|
|
140
|
-
localize: "https://localize.topolo.app",
|
|
141
|
-
mail: "https://mail.topolo.app",
|
|
142
|
-
mdm: "https://mdm.topolo.app",
|
|
143
|
-
messages: "https://messages.topolo.app",
|
|
144
|
-
nexus: "https://nexus.topolo.app",
|
|
145
|
-
notify: "https://notify.topolo.app",
|
|
146
|
-
observability_watch: "https://observability-watch.topolo.app",
|
|
147
|
-
one: "https://www.topolo.app",
|
|
148
|
-
p2p: "https://p2p.topolo.app",
|
|
149
|
-
pay: "https://pay.topolo.app",
|
|
150
|
-
people: "https://people.topolo.app",
|
|
151
|
-
"quro.api": "https://api.ol0.me",
|
|
152
|
-
"quro.redirect": "https://ol0.me",
|
|
153
|
-
roadmapper: "https://roadmapper.topolo.app",
|
|
154
|
-
sign: "https://sign.topolo.app",
|
|
155
|
-
social_studio: "https://studio.topolo.app",
|
|
156
|
-
socialize: "https://socialize.topolo.app",
|
|
157
|
-
spaces: "https://spaces.topolo.app",
|
|
158
|
-
status: "https://status.topolo.app",
|
|
159
|
-
success: "https://success.topolo.app",
|
|
160
|
-
support: "https://support.topolo.app",
|
|
161
|
-
survey: "https://survey.topolo.app",
|
|
162
|
-
voice: "https://voice.topolo.app",
|
|
163
|
-
web: "https://web.topolo.app"
|
|
114
|
+
developers: "https://developers.topolo.app"
|
|
164
115
|
};
|
|
165
116
|
var APPLICATIONS = {
|
|
166
117
|
"admin": {
|
|
@@ -1886,7 +1837,145 @@ var APPLICATIONS = {
|
|
|
1886
1837
|
]
|
|
1887
1838
|
}
|
|
1888
1839
|
};
|
|
1889
|
-
|
|
1840
|
+
function friendlyAppId(entry) {
|
|
1841
|
+
for (const value of [entry.slug, entry.name, entry.appId]) {
|
|
1842
|
+
if (typeof value !== "string" || !value.trim()) continue;
|
|
1843
|
+
const normalized = value.trim().toLowerCase().replace(/\s+/g, "-");
|
|
1844
|
+
const withoutPrefix = normalized.replace(/^(?:app[_-])?topolo[-_]+/, "");
|
|
1845
|
+
if (withoutPrefix) return withoutPrefix;
|
|
1846
|
+
}
|
|
1847
|
+
return entry.appId;
|
|
1848
|
+
}
|
|
1849
|
+
function idVariants(value) {
|
|
1850
|
+
const normalized = value.trim().toLowerCase().replace(/\s+/g, "-");
|
|
1851
|
+
return [.../* @__PURE__ */ new Set([
|
|
1852
|
+
normalized,
|
|
1853
|
+
normalized.replace(/-/g, "_"),
|
|
1854
|
+
normalized.replace(/_/g, "-")
|
|
1855
|
+
])].filter(Boolean);
|
|
1856
|
+
}
|
|
1857
|
+
var STATIC_APPLICATIONS = APPLICATIONS;
|
|
1858
|
+
function staticApplicationForId(id) {
|
|
1859
|
+
for (const variant of idVariants(id)) {
|
|
1860
|
+
const entry = STATIC_APPLICATIONS[variant];
|
|
1861
|
+
if (entry) return entry;
|
|
1862
|
+
}
|
|
1863
|
+
return null;
|
|
1864
|
+
}
|
|
1865
|
+
function applicationEntryFromCatalog(live) {
|
|
1866
|
+
const id = friendlyAppId(live);
|
|
1867
|
+
return {
|
|
1868
|
+
id,
|
|
1869
|
+
appDir: "-",
|
|
1870
|
+
name: live.name ?? live.slug ?? live.appId,
|
|
1871
|
+
packageName: null,
|
|
1872
|
+
productionUrl: live.launchUrl ?? live.apiBaseUrl ?? null,
|
|
1873
|
+
services: live.apiBaseUrl ? [id] : [],
|
|
1874
|
+
deployTargets: []
|
|
1875
|
+
};
|
|
1876
|
+
}
|
|
1877
|
+
var DIRECTORY_PAGE_LIMIT = 100;
|
|
1878
|
+
var DIRECTORY_MAX_PAGES = 100;
|
|
1879
|
+
function staticApplicationDirectory() {
|
|
1880
|
+
const applications = Object.entries(STATIC_APPLICATIONS).map(([id, application]) => ({
|
|
1881
|
+
id,
|
|
1882
|
+
application,
|
|
1883
|
+
source: "static",
|
|
1884
|
+
live: null
|
|
1885
|
+
})).sort((left, right) => left.id.localeCompare(right.id));
|
|
1886
|
+
return { source: "static_fallback", applications };
|
|
1887
|
+
}
|
|
1888
|
+
function directoryApplicationFromLive(live) {
|
|
1889
|
+
const id = friendlyAppId(live);
|
|
1890
|
+
return {
|
|
1891
|
+
id,
|
|
1892
|
+
// Prefer the static snapshot's richer repo/deploy metadata when the live
|
|
1893
|
+
// registry confirms the app; synthesize from the live entry otherwise.
|
|
1894
|
+
application: staticApplicationForId(id) ?? applicationEntryFromCatalog(live),
|
|
1895
|
+
source: "live",
|
|
1896
|
+
live
|
|
1897
|
+
};
|
|
1898
|
+
}
|
|
1899
|
+
async function listApplicationDirectory(client) {
|
|
1900
|
+
if (!client) return staticApplicationDirectory();
|
|
1901
|
+
let services;
|
|
1902
|
+
try {
|
|
1903
|
+
services = [];
|
|
1904
|
+
let cursor;
|
|
1905
|
+
for (let page = 0; page < DIRECTORY_MAX_PAGES; page += 1) {
|
|
1906
|
+
const result = await client.searchServices({
|
|
1907
|
+
...cursor ? { cursor } : {},
|
|
1908
|
+
limit: DIRECTORY_PAGE_LIMIT
|
|
1909
|
+
});
|
|
1910
|
+
services.push(...result.services);
|
|
1911
|
+
if (!result.page.nextCursor) break;
|
|
1912
|
+
cursor = result.page.nextCursor;
|
|
1913
|
+
}
|
|
1914
|
+
} catch {
|
|
1915
|
+
return staticApplicationDirectory();
|
|
1916
|
+
}
|
|
1917
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1918
|
+
for (const live of services) {
|
|
1919
|
+
const entry = directoryApplicationFromLive(live);
|
|
1920
|
+
if (!seen.has(entry.id)) seen.set(entry.id, entry);
|
|
1921
|
+
}
|
|
1922
|
+
return {
|
|
1923
|
+
source: "live",
|
|
1924
|
+
applications: [...seen.values()].sort((left, right) => left.id.localeCompare(right.id))
|
|
1925
|
+
};
|
|
1926
|
+
}
|
|
1927
|
+
function matchesDirectoryApplication(app, needle) {
|
|
1928
|
+
const candidates = new Set(idVariants(needle));
|
|
1929
|
+
const keys = [
|
|
1930
|
+
app.id,
|
|
1931
|
+
app.application.id,
|
|
1932
|
+
app.application.name,
|
|
1933
|
+
app.live?.appId,
|
|
1934
|
+
app.live?.slug,
|
|
1935
|
+
app.live?.name
|
|
1936
|
+
];
|
|
1937
|
+
for (const key of keys) {
|
|
1938
|
+
if (typeof key !== "string" || !key.trim()) continue;
|
|
1939
|
+
for (const variant of idVariants(key)) {
|
|
1940
|
+
if (candidates.has(variant)) return true;
|
|
1941
|
+
}
|
|
1942
|
+
for (const variant of idVariants(friendlyAppId({ appId: key }))) {
|
|
1943
|
+
if (candidates.has(variant)) return true;
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
return false;
|
|
1947
|
+
}
|
|
1948
|
+
function formatDirectoryApplicationIds(directory) {
|
|
1949
|
+
const ids = directory.applications.map((app) => app.id).sort();
|
|
1950
|
+
const preview = ids.slice(0, 50).join(", ");
|
|
1951
|
+
const suffix = ids.length > 50 ? `, ... +${ids.length - 50} more` : "";
|
|
1952
|
+
const label = directory.source === "live" ? "Applications available to this credential" : "Applications in the bundled static snapshot (live registry unreachable)";
|
|
1953
|
+
return `${label}: ${preview}${suffix}`;
|
|
1954
|
+
}
|
|
1955
|
+
async function resolveApplicationDirectoryEntry(client, application) {
|
|
1956
|
+
const needle = typeof application === "string" ? application.trim() : "";
|
|
1957
|
+
if (!needle) {
|
|
1958
|
+
throw new TopoloSdkError("unknown_application", "application is required");
|
|
1959
|
+
}
|
|
1960
|
+
if (client) {
|
|
1961
|
+
let live = null;
|
|
1962
|
+
try {
|
|
1963
|
+
live = await client.getService(needle);
|
|
1964
|
+
} catch {
|
|
1965
|
+
live = null;
|
|
1966
|
+
}
|
|
1967
|
+
if (live) return directoryApplicationFromLive(live);
|
|
1968
|
+
}
|
|
1969
|
+
const directory = await listApplicationDirectory(client);
|
|
1970
|
+
const match = directory.applications.find((app) => matchesDirectoryApplication(app, needle));
|
|
1971
|
+
if (match) return match;
|
|
1972
|
+
throw new TopoloSdkError(
|
|
1973
|
+
"unknown_application",
|
|
1974
|
+
`Unknown application "${application}". ${formatDirectoryApplicationIds(directory)}`
|
|
1975
|
+
);
|
|
1976
|
+
}
|
|
1977
|
+
var STATIC_APPLICATIONS2 = APPLICATIONS;
|
|
1978
|
+
var APPLICATION_REQUIREMENTS_VERSION = "2026-08-11.1";
|
|
1890
1979
|
var APPLICATION_REQUIREMENTS = [
|
|
1891
1980
|
{
|
|
1892
1981
|
id: "platform-metadata",
|
|
@@ -1896,10 +1985,10 @@ var APPLICATION_REQUIREMENTS = [
|
|
|
1896
1985
|
evidence: [
|
|
1897
1986
|
"topolo.cloudcontrol.json exists for every deployed app surface",
|
|
1898
1987
|
"package.json names the package or app when the repo ships code",
|
|
1899
|
-
"The
|
|
1988
|
+
"The live platform registry exposes the app through topolo apps and MCP discovery"
|
|
1900
1989
|
],
|
|
1901
1990
|
implementation: [
|
|
1902
|
-
"
|
|
1991
|
+
"Register the app in the live platform registry (Auth service catalog) before exposing it to agents",
|
|
1903
1992
|
"Keep production URLs, Worker names, Pages projects, routes, domains, and bindings current in CloudControl metadata",
|
|
1904
1993
|
"Do not leave a new Topolo* app directory without an explicit application ID"
|
|
1905
1994
|
]
|
|
@@ -1974,7 +2063,7 @@ var APPLICATION_REQUIREMENTS = [
|
|
|
1974
2063
|
implementation: [
|
|
1975
2064
|
"Add production Worker api_url metadata and sdk_app_id for every agent-callable API target",
|
|
1976
2065
|
"Mark browser, documentation, and runtime-only Worker targets with agent_callable:false",
|
|
1977
|
-
"Expose stable app IDs through
|
|
2066
|
+
"Expose stable app IDs through live catalog discovery",
|
|
1978
2067
|
"Keep typed SDK/CLI/MCP surfaces in sync when an API contract stabilizes"
|
|
1979
2068
|
]
|
|
1980
2069
|
},
|
|
@@ -2094,15 +2183,24 @@ function applicationRequirementScopes(application) {
|
|
|
2094
2183
|
}
|
|
2095
2184
|
return Array.from(scopes);
|
|
2096
2185
|
}
|
|
2186
|
+
function fallbackApplication(id) {
|
|
2187
|
+
const entry = STATIC_APPLICATIONS2[id];
|
|
2188
|
+
if (!entry) {
|
|
2189
|
+
throw new Error(
|
|
2190
|
+
`Unknown application "${id}" in the static fallback snapshot. Resolve applications from the live registry (resolveApplicationDirectoryEntry) and pass the entry directly.`
|
|
2191
|
+
);
|
|
2192
|
+
}
|
|
2193
|
+
return entry;
|
|
2194
|
+
}
|
|
2097
2195
|
function requirementsForApplication(applicationOrId) {
|
|
2098
|
-
const application = typeof applicationOrId === "string" ?
|
|
2196
|
+
const application = typeof applicationOrId === "string" ? fallbackApplication(applicationOrId) : applicationOrId;
|
|
2099
2197
|
const scopes = new Set(applicationRequirementScopes(application));
|
|
2100
2198
|
return APPLICATION_REQUIREMENTS.filter(
|
|
2101
2199
|
(requirement) => requirement.appliesTo.some((scope) => scopes.has(scope))
|
|
2102
2200
|
);
|
|
2103
2201
|
}
|
|
2104
2202
|
function auditApplicationRequirements(applicationOrId) {
|
|
2105
|
-
const application = typeof applicationOrId === "string" ?
|
|
2203
|
+
const application = typeof applicationOrId === "string" ? fallbackApplication(applicationOrId) : applicationOrId;
|
|
2106
2204
|
const scopes = applicationRequirementScopes(application);
|
|
2107
2205
|
const findings = requirementsForApplication(application).map(
|
|
2108
2206
|
(requirement) => evaluateRequirement(application, requirement)
|
|
@@ -2115,10 +2213,12 @@ function auditApplicationRequirements(applicationOrId) {
|
|
|
2115
2213
|
findings
|
|
2116
2214
|
};
|
|
2117
2215
|
}
|
|
2118
|
-
function
|
|
2119
|
-
|
|
2120
|
-
(
|
|
2216
|
+
function auditApplicationEntries(applications) {
|
|
2217
|
+
return buildAuditReport(
|
|
2218
|
+
applications.map((application) => auditApplicationRequirements(application))
|
|
2121
2219
|
);
|
|
2220
|
+
}
|
|
2221
|
+
function buildAuditReport(applications) {
|
|
2122
2222
|
const migrationQueue = applications.flatMap(
|
|
2123
2223
|
(audit) => audit.findings.filter((finding2) => finding2.status !== "met").map((finding2) => ({
|
|
2124
2224
|
applicationId: audit.application.id,
|
|
@@ -3421,8 +3521,9 @@ var TopoloClient = class _TopoloClient {
|
|
|
3421
3521
|
});
|
|
3422
3522
|
}
|
|
3423
3523
|
/**
|
|
3424
|
-
*
|
|
3425
|
-
*
|
|
3524
|
+
* @deprecated Static fallback snapshot only. Use `searchServices()` (the
|
|
3525
|
+
* live credential-scoped registry) for anything that decides behavior; this
|
|
3526
|
+
* exists for offline packaging audits when the registry is unreachable.
|
|
3426
3527
|
*/
|
|
3427
3528
|
listBundledServices() {
|
|
3428
3529
|
const apps = Object.values(APPLICATIONS);
|
|
@@ -4079,57 +4180,8 @@ var TopoloHttpError2 = class extends TopoloSdkError2 {
|
|
|
4079
4180
|
}
|
|
4080
4181
|
};
|
|
4081
4182
|
var APP_API_URLS2 = {
|
|
4082
|
-
agent: "https://agent.topolo.app",
|
|
4083
4183
|
auth: "https://auth.topolo.app",
|
|
4084
|
-
|
|
4085
|
-
blog: "https://blog.topolo.app",
|
|
4086
|
-
books: "https://books.topolo.app",
|
|
4087
|
-
brand: "https://brand.topolo.app",
|
|
4088
|
-
bugfix: "https://bugfix.topolo.app",
|
|
4089
|
-
bytes: "https://bytes.topolo.app",
|
|
4090
|
-
calendar: "https://calendar.topolo.app",
|
|
4091
|
-
campaigns: "https://campaigns.topolo.app",
|
|
4092
|
-
capacity: "https://capacity.topolo.app",
|
|
4093
|
-
chat: "https://chat.topolo.app",
|
|
4094
|
-
commerce: "https://commerce.topolo.app",
|
|
4095
|
-
compose: "https://compose.topolo.app",
|
|
4096
|
-
consent: "https://consent.topolo.app",
|
|
4097
|
-
crm: "https://crm.topolo.app",
|
|
4098
|
-
design: "https://design.topolo.app",
|
|
4099
|
-
developers: "https://developers.topolo.app",
|
|
4100
|
-
director: "https://director.topolo.app",
|
|
4101
|
-
feed: "https://feed.topolo.app",
|
|
4102
|
-
flow: "https://flow.topolo.app",
|
|
4103
|
-
forecast: "https://forecast.topolo.app",
|
|
4104
|
-
forms: "https://forms.topolo.app",
|
|
4105
|
-
home: "https://home.topolo.app",
|
|
4106
|
-
insights: "https://insights.topolo.app",
|
|
4107
|
-
inventory: "https://inventory.topolo.app",
|
|
4108
|
-
learn: "https://learn.topolo.app",
|
|
4109
|
-
localize: "https://localize.topolo.app",
|
|
4110
|
-
mail: "https://mail.topolo.app",
|
|
4111
|
-
mdm: "https://mdm.topolo.app",
|
|
4112
|
-
messages: "https://messages.topolo.app",
|
|
4113
|
-
nexus: "https://nexus.topolo.app",
|
|
4114
|
-
notify: "https://notify.topolo.app",
|
|
4115
|
-
observability_watch: "https://observability-watch.topolo.app",
|
|
4116
|
-
one: "https://www.topolo.app",
|
|
4117
|
-
p2p: "https://p2p.topolo.app",
|
|
4118
|
-
pay: "https://pay.topolo.app",
|
|
4119
|
-
people: "https://people.topolo.app",
|
|
4120
|
-
"quro.api": "https://api.ol0.me",
|
|
4121
|
-
"quro.redirect": "https://ol0.me",
|
|
4122
|
-
roadmapper: "https://roadmapper.topolo.app",
|
|
4123
|
-
sign: "https://sign.topolo.app",
|
|
4124
|
-
social_studio: "https://studio.topolo.app",
|
|
4125
|
-
socialize: "https://socialize.topolo.app",
|
|
4126
|
-
spaces: "https://spaces.topolo.app",
|
|
4127
|
-
status: "https://status.topolo.app",
|
|
4128
|
-
success: "https://success.topolo.app",
|
|
4129
|
-
support: "https://support.topolo.app",
|
|
4130
|
-
survey: "https://survey.topolo.app",
|
|
4131
|
-
voice: "https://voice.topolo.app",
|
|
4132
|
-
web: "https://web.topolo.app"
|
|
4184
|
+
developers: "https://developers.topolo.app"
|
|
4133
4185
|
};
|
|
4134
4186
|
var DEFAULT_APP_URLS2 = APP_API_URLS2;
|
|
4135
4187
|
function resolveServiceUrl2(service, overrides) {
|
|
@@ -6523,12 +6575,6 @@ function normalizeContainerAppId(value, surfaceModel) {
|
|
|
6523
6575
|
function normalizeApplicationId(application) {
|
|
6524
6576
|
const raw = application.trim().toLowerCase();
|
|
6525
6577
|
const normalized = raw.replace(/-/g, "_");
|
|
6526
|
-
if (Object.prototype.hasOwnProperty.call(APPLICATIONS, raw)) {
|
|
6527
|
-
return raw;
|
|
6528
|
-
}
|
|
6529
|
-
if (Object.prototype.hasOwnProperty.call(APPLICATIONS, normalized)) {
|
|
6530
|
-
return normalized;
|
|
6531
|
-
}
|
|
6532
6578
|
if (/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/.test(raw) || /^[a-z0-9](?:[a-z0-9_]*[a-z0-9])?$/.test(raw)) {
|
|
6533
6579
|
return normalized;
|
|
6534
6580
|
}
|
|
@@ -9914,7 +9960,7 @@ function applicationScaffoldPayload(application, options = {}) {
|
|
|
9914
9960
|
const requestedId = normalizeApplicationId(application);
|
|
9915
9961
|
const id = target === "platform" ? normalizeFirstPartyApplicationId(requestedId) : requestedId;
|
|
9916
9962
|
const slug = toSlug(id);
|
|
9917
|
-
const catalogApplication =
|
|
9963
|
+
const catalogApplication = options.catalogApplication ?? null;
|
|
9918
9964
|
const browser = options.browser !== false;
|
|
9919
9965
|
const api = options.api ?? target === "platform";
|
|
9920
9966
|
const audience = normalizeAudience(
|
|
@@ -11550,7 +11596,6 @@ function registerApplicationReconcileCommand(parent, ownerType, dependencies = {
|
|
|
11550
11596
|
}
|
|
11551
11597
|
|
|
11552
11598
|
// src/commands/apps.ts
|
|
11553
|
-
var APPLICATION_IDS = Object.keys(APPLICATIONS).sort();
|
|
11554
11599
|
var CLOUDCONTROL_LOCAL_APPLICATION = {
|
|
11555
11600
|
id: "cloudcontrol",
|
|
11556
11601
|
appDir: "TopoloCloudControl",
|
|
@@ -11560,6 +11605,21 @@ var CLOUDCONTROL_LOCAL_APPLICATION = {
|
|
|
11560
11605
|
services: [],
|
|
11561
11606
|
deployTargets: []
|
|
11562
11607
|
};
|
|
11608
|
+
async function directoryClient() {
|
|
11609
|
+
try {
|
|
11610
|
+
const topolo = await buildClient();
|
|
11611
|
+
return topolo ? topolo.client : null;
|
|
11612
|
+
} catch {
|
|
11613
|
+
return null;
|
|
11614
|
+
}
|
|
11615
|
+
}
|
|
11616
|
+
async function resolveScaffoldCatalogApplication(application) {
|
|
11617
|
+
try {
|
|
11618
|
+
return await resolveApplication(application, await directoryClient());
|
|
11619
|
+
} catch {
|
|
11620
|
+
return null;
|
|
11621
|
+
}
|
|
11622
|
+
}
|
|
11563
11623
|
function registerAppsCommand(program2) {
|
|
11564
11624
|
const apps = program2.command("apps").description("Search Topolo platform applications available to the current credential").option("-q, --query <query>", "Filter by app id, slug, or name").option("--cursor <cursor>", "Continuation cursor from the previous page").option("--limit <limit>", "Page size (1-100)", "25").option("--json", "Output JSON", true).option("--no-json", "Output human-readable table").action(async (opts) => {
|
|
11565
11625
|
const mode = resolveOutputMode(opts.json);
|
|
@@ -11597,10 +11657,10 @@ function registerAppsCommand(program2) {
|
|
|
11597
11657
|
});
|
|
11598
11658
|
apps.command("requirements [application]").description(
|
|
11599
11659
|
"Show the versioned Topolo application-build requirements, optionally filtered to one app."
|
|
11600
|
-
).option("--json", "Output JSON", true).option("--no-json", "Output human-readable details").action((application, opts) => {
|
|
11660
|
+
).option("--json", "Output JSON", true).option("--no-json", "Output human-readable details").action(async (application, opts) => {
|
|
11601
11661
|
const mode = resolveOutputMode(opts.json);
|
|
11602
11662
|
try {
|
|
11603
|
-
const payload = applicationRequirementsPayload(application);
|
|
11663
|
+
const payload = await applicationRequirementsPayload(application, await directoryClient());
|
|
11604
11664
|
emit(payload, mode, () => formatRequirements(payload));
|
|
11605
11665
|
} catch (err) {
|
|
11606
11666
|
fail(err, mode);
|
|
@@ -11611,12 +11671,13 @@ function registerAppsCommand(program2) {
|
|
|
11611
11671
|
).option("--json", "Output JSON", true).option("--no-json", "Output human-readable table").option("--local", "Inspect the local Topolo checkout for filesystem-backed evidence").option("--repo-root <path>", "Topolo checkout root to inspect when --local is set").option(
|
|
11612
11672
|
"--fail-on <status>",
|
|
11613
11673
|
"Exit non-zero when audit has findings at this severity or worse: missing, needs_review, partial"
|
|
11614
|
-
).action((application, opts) => {
|
|
11674
|
+
).action(async (application, opts) => {
|
|
11615
11675
|
const mode = resolveOutputMode(opts.json);
|
|
11616
11676
|
try {
|
|
11617
|
-
const payload = applicationAuditPayload(application, {
|
|
11677
|
+
const payload = await applicationAuditPayload(application, {
|
|
11618
11678
|
local: opts.local,
|
|
11619
|
-
repoRoot: opts.repoRoot
|
|
11679
|
+
repoRoot: opts.repoRoot,
|
|
11680
|
+
client: await directoryClient()
|
|
11620
11681
|
});
|
|
11621
11682
|
const gate = opts.failOn ? evaluateApplicationAuditGate(payload, opts.failOn) : null;
|
|
11622
11683
|
const output2 = gate ? { ...payload, conformanceGate: gate } : payload;
|
|
@@ -11636,10 +11697,13 @@ function registerAppsCommand(program2) {
|
|
|
11636
11697
|
});
|
|
11637
11698
|
apps.command("record-evidence <application>").description(
|
|
11638
11699
|
"Stamp <repo>/.topolo/evidence.json with the latest CI gate results so the audit can flip verification-gates / observability-and-audit / canonical-docs from partial to met when the recorded run is fresh (< 24h)."
|
|
11639
|
-
).option("--json", "Output JSON", true).option("--no-json", "Output human-readable summary").option("--app-root <path>", "Path to the application repo root (defaults to cwd)").option("--build", "Mark the latest build as successful").option("--typecheck", "Mark the latest typecheck as successful").option("--test", "Mark the latest test run as successful").option("--docs-validate", "Mark the latest TopoloDocs npm run validate as successful").option("--smoke <url>", "Mark the latest live smoke as successful against this URL").option("--commit <sha>", "Override the commit hash (defaults to git HEAD)").action((application, opts) => {
|
|
11700
|
+
).option("--json", "Output JSON", true).option("--no-json", "Output human-readable summary").option("--app-root <path>", "Path to the application repo root (defaults to cwd)").option("--build", "Mark the latest build as successful").option("--typecheck", "Mark the latest typecheck as successful").option("--test", "Mark the latest test run as successful").option("--docs-validate", "Mark the latest TopoloDocs npm run validate as successful").option("--smoke <url>", "Mark the latest live smoke as successful against this URL").option("--commit <sha>", "Override the commit hash (defaults to git HEAD)").action(async (application, opts) => {
|
|
11640
11701
|
const mode = resolveOutputMode(opts.json);
|
|
11641
11702
|
try {
|
|
11642
|
-
const payload = recordApplicationEvidence(application,
|
|
11703
|
+
const payload = await recordApplicationEvidence(application, {
|
|
11704
|
+
...opts,
|
|
11705
|
+
client: await directoryClient()
|
|
11706
|
+
});
|
|
11643
11707
|
emit(payload, mode, () => formatEvidence(payload));
|
|
11644
11708
|
} catch (err) {
|
|
11645
11709
|
fail(err, mode);
|
|
@@ -11661,6 +11725,7 @@ function registerAppsCommand(program2) {
|
|
|
11661
11725
|
try {
|
|
11662
11726
|
const api = resolveScaffoldApiOption(opts.api, opts.withApi);
|
|
11663
11727
|
const payload = applicationScaffoldPayload(application, {
|
|
11728
|
+
catalogApplication: await resolveScaffoldCatalogApplication(application),
|
|
11664
11729
|
appDir: opts.appDir,
|
|
11665
11730
|
name: opts.name,
|
|
11666
11731
|
packageName: opts.packageName,
|
|
@@ -11722,14 +11787,11 @@ function parsePageSize2(value) {
|
|
|
11722
11787
|
}
|
|
11723
11788
|
return parsed;
|
|
11724
11789
|
}
|
|
11725
|
-
function resolveApplication(application) {
|
|
11726
|
-
const
|
|
11727
|
-
|
|
11728
|
-
throw new Error(`Unknown application "${application}". ${formatKnownValues(APPLICATION_IDS, "applications")}`);
|
|
11729
|
-
}
|
|
11730
|
-
return APPLICATIONS[id];
|
|
11790
|
+
async function resolveApplication(application, client = null) {
|
|
11791
|
+
const resolved = await resolveApplicationDirectoryEntry(client, application);
|
|
11792
|
+
return resolved.application;
|
|
11731
11793
|
}
|
|
11732
|
-
function applicationRequirementsPayload(application) {
|
|
11794
|
+
async function applicationRequirementsPayload(application, client = null) {
|
|
11733
11795
|
if (!application) {
|
|
11734
11796
|
return {
|
|
11735
11797
|
version: APPLICATION_REQUIREMENTS_VERSION,
|
|
@@ -11738,7 +11800,7 @@ function applicationRequirementsPayload(application) {
|
|
|
11738
11800
|
requirements: [...APPLICATION_REQUIREMENTS]
|
|
11739
11801
|
};
|
|
11740
11802
|
}
|
|
11741
|
-
const app = resolveApplication(application);
|
|
11803
|
+
const app = await resolveApplication(application, client);
|
|
11742
11804
|
return {
|
|
11743
11805
|
version: APPLICATION_REQUIREMENTS_VERSION,
|
|
11744
11806
|
application: app,
|
|
@@ -11746,18 +11808,21 @@ function applicationRequirementsPayload(application) {
|
|
|
11746
11808
|
requirements: requirementsForApplication(app)
|
|
11747
11809
|
};
|
|
11748
11810
|
}
|
|
11749
|
-
function applicationAuditPayload(application, options = {}) {
|
|
11811
|
+
async function applicationAuditPayload(application, options = {}) {
|
|
11812
|
+
const client = options.client ?? null;
|
|
11750
11813
|
const requestedId = application?.trim().toLowerCase();
|
|
11751
11814
|
const report = requestedId === "cloudcontrol" && options.local ? {
|
|
11752
11815
|
version: APPLICATION_REQUIREMENTS_VERSION,
|
|
11753
11816
|
applications: [auditApplicationRequirements(CLOUDCONTROL_LOCAL_APPLICATION)],
|
|
11754
11817
|
migrationQueue: []
|
|
11755
|
-
} : application ?
|
|
11818
|
+
} : application ? auditApplicationEntries([await resolveApplication(application, client)]) : auditApplicationEntries(
|
|
11819
|
+
(await listApplicationDirectory(client)).applications.map((app) => app.application)
|
|
11820
|
+
);
|
|
11756
11821
|
if (!options.local) return report;
|
|
11757
11822
|
return enrichApplicationAuditWithLocalEvidence(report, { repoRoot: options.repoRoot });
|
|
11758
11823
|
}
|
|
11759
|
-
function recordApplicationEvidence(application, options = {}) {
|
|
11760
|
-
const appId = resolveApplication(application).id;
|
|
11824
|
+
async function recordApplicationEvidence(application, options = {}) {
|
|
11825
|
+
const appId = (await resolveApplication(application, options.client ?? null)).id;
|
|
11761
11826
|
const root = path6.resolve(options.appRoot ?? process.cwd());
|
|
11762
11827
|
if (!existsSync4(root)) {
|
|
11763
11828
|
throw new Error(`Application root does not exist: ${root}`);
|
|
@@ -11888,22 +11953,7 @@ function applicationUrl(application) {
|
|
|
11888
11953
|
return application.apiBaseUrl ?? application.launchUrl ?? application.productionUrl ?? null;
|
|
11889
11954
|
}
|
|
11890
11955
|
function displayCatalogId(entry) {
|
|
11891
|
-
|
|
11892
|
-
if (typeof value !== "string" || !value.trim()) continue;
|
|
11893
|
-
const candidates = catalogIdCandidates(value);
|
|
11894
|
-
const withoutTopolo = candidates.find((candidate) => !candidate.startsWith("topolo-"));
|
|
11895
|
-
if (withoutTopolo) return withoutTopolo;
|
|
11896
|
-
if (candidates[0]) return candidates[0];
|
|
11897
|
-
}
|
|
11898
|
-
return entry.appId;
|
|
11899
|
-
}
|
|
11900
|
-
function catalogIdCandidates(value) {
|
|
11901
|
-
const normalized = value.trim().toLowerCase().replace(/\s+/g, "-");
|
|
11902
|
-
const withoutTopolo = normalized.startsWith("topolo-") ? normalized.slice("topolo-".length) : normalized;
|
|
11903
|
-
return [.../* @__PURE__ */ new Set([
|
|
11904
|
-
normalized,
|
|
11905
|
-
withoutTopolo
|
|
11906
|
-
])].filter(Boolean);
|
|
11956
|
+
return friendlyAppId(entry);
|
|
11907
11957
|
}
|
|
11908
11958
|
function formatRequirements(payload) {
|
|
11909
11959
|
const lines = [
|
|
@@ -12067,12 +12117,6 @@ function normalizeFailOn(value) {
|
|
|
12067
12117
|
}
|
|
12068
12118
|
throw new Error("Invalid --fail-on value. Use missing, needs_review, or partial.");
|
|
12069
12119
|
}
|
|
12070
|
-
function formatKnownValues(values, label) {
|
|
12071
|
-
const sorted = [...values].sort();
|
|
12072
|
-
const preview = sorted.slice(0, 25).join(", ");
|
|
12073
|
-
const suffix = sorted.length > 25 ? `, ... +${sorted.length - 25} more` : "";
|
|
12074
|
-
return `Run discovery for the full ${label} list. Known snapshot sample: ${preview}${suffix}`;
|
|
12075
|
-
}
|
|
12076
12120
|
function statusesAtOrWorse(threshold) {
|
|
12077
12121
|
if (threshold === "missing") return ["missing"];
|
|
12078
12122
|
if (threshold === "needs_review") return ["missing", "needs_review"];
|
|
@@ -12274,6 +12318,7 @@ function registerPlatformCommand(program2) {
|
|
|
12274
12318
|
}
|
|
12275
12319
|
const api = resolveScaffoldApiOption(opts.api, opts.withApi);
|
|
12276
12320
|
const payload = applicationScaffoldPayload(application, {
|
|
12321
|
+
catalogApplication: await resolveScaffoldCatalogApplication(application),
|
|
12277
12322
|
appDir: opts.appDir,
|
|
12278
12323
|
name: opts.name,
|
|
12279
12324
|
packageName: opts.packageName,
|
|
@@ -12525,15 +12570,7 @@ function isStagingUrl(value) {
|
|
|
12525
12570
|
return url.includes(".stg.topolo.us") || url.includes("localhost") || url.includes("127.0.0.1") || url.includes("topolo-staging");
|
|
12526
12571
|
}
|
|
12527
12572
|
function displayAppId(entry) {
|
|
12528
|
-
|
|
12529
|
-
if (typeof value !== "string" || !value.trim()) continue;
|
|
12530
|
-
for (const candidate of appIdCandidates(value)) {
|
|
12531
|
-
if (Object.prototype.hasOwnProperty.call(DEFAULT_APP_URLS, candidate)) {
|
|
12532
|
-
return candidate;
|
|
12533
|
-
}
|
|
12534
|
-
}
|
|
12535
|
-
}
|
|
12536
|
-
return appIdCandidates(entry.slug || entry.appId)[0] || entry.appId;
|
|
12573
|
+
return friendlyAppId(entry);
|
|
12537
12574
|
}
|
|
12538
12575
|
function defaultServiceUrl(id, entry) {
|
|
12539
12576
|
return resolveCatalogServiceUrl(entry, { serviceKey: id });
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@topolo/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"topoloPublishedVersion": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"topoloPublishedVersion": "0.7.0",
|
|
5
5
|
"description": "Command-line interface for Topolo developers, operators, and agents, with internal first-party scaffolding available under the topolo platform namespace.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
package/skills/codex/AGENTS.md
CHANGED
|
@@ -4,7 +4,7 @@ This file teaches an agent how to interact with the Topolo platform via the `top
|
|
|
4
4
|
|
|
5
5
|
## What the platform is
|
|
6
6
|
|
|
7
|
-
Topolo is a multi-app SaaS platform. The CLI and MCP server both use `@topolo/sdk`;
|
|
7
|
+
Topolo is a multi-app SaaS platform. The CLI and MCP server both use `@topolo/sdk`; every application resolves from the live credential-scoped registry, so newly registered apps and API/technical services work immediately — there is no bundled application catalog to rely on or wait for.
|
|
8
8
|
|
|
9
9
|
- Use `topolo apps --json` or the MCP `topolo_search_applications` tool to discover platform applications, including browser-only Worker apps.
|
|
10
10
|
- Use `topolo apps requirements <application_id> --json` or the MCP `topolo_list_application_requirements` tool before creating or expanding a Topolo app.
|
|
@@ -12,7 +12,7 @@ Topolo is a multi-app SaaS platform. The CLI and MCP server both use `@topolo/sd
|
|
|
12
12
|
- Use `topolo services --json` or the MCP `topolo_search_applications` tool to discover callable app ids and effective URLs.
|
|
13
13
|
- Use `topolo actions --service <app> --json` or MCP `topolo_search_actions` to discover callable operations granted to the current credential; invoke automatic reads with `topolo_read_action` and confirmation-gated operations with `topolo_call_action`.
|
|
14
14
|
- Use `topolo actions capabilities`, `actions examples`, `actions validate`, and `actions plan` (or their MCP equivalents) to obtain schemas, examples, verification, and rollback before execution.
|
|
15
|
-
- The generic `api` command and MCP `topolo_api_call` tool can reach
|
|
15
|
+
- The generic `api` command and MCP `topolo_api_call` tool can reach any live Auth-catalog application or API/technical service when no action contract exists yet; discover ids with `topolo apps --json` first.
|
|
16
16
|
|
|
17
17
|
Every call is scoped to the organization embedded in the credential. There is no `--org` flag anywhere — attempting to target another org will fail.
|
|
18
18
|
|