ReMe/reme_studio/app/workspace-files.ts
jinliyl ef3f99f019
refactor(packaging): reorganize published packages (#495)
* refactor(packaging): reorganize published packages

* fix(packaging): install AgentScope extra in wheel smoke

* docs: align package guides and documentation site

* ci(workflow): add core dependency verification step in Python package build

- Add a workflow step to verify released core dependencies by installing the wheel with core extras
- Assert the presence of the static index.html file to ensure proper package contents
- Create and use a temporary virtual environment for isolation during verification
- Keep existing artifacts upload step intact and conditional on inputs.upload_artifacts flag

* fix(ci): update package installation dependencies in Windows workflow

- Change pip install from editable reme_studio and core to only dev and as extras
- Remove installation of reme_studio and core to streamline dependency setup
- Ensure Windows CI uses the correct extras for testing environment

* fix(tests): add missing commas in toml file reads in package version tests

- Added trailing commas in the tomllib.loads calls for auto-fin and daily_paper configs
- Ensured consistent syntax to prevent potential tuple misinterpretation
- Improved readability and correctness of the test setup code

* fix(packaging): protect qwenpaw releases and test Studio health
2026-08-27 14:02:09 +08:00

109 lines
3 KiB
TypeScript

import type { TreeNode } from "./types";
const defaults = ["md", "txt"];
export const WORKSPACE_FILE_LIMIT = 5000;
export interface WorkspaceFileListing {
paths: string[];
limited: boolean;
}
export function workspaceFileListing(
items: unknown,
limit = WORKSPACE_FILE_LIMIT,
): WorkspaceFileListing {
const paths = Array.isArray(items)
? items.filter((item): item is string => typeof item === "string")
: [];
return { paths, limited: paths.length >= limit };
}
export type WorkspaceDirectoryConfig = {
daily_dir: string;
digest_dir: string;
};
export type WorkspaceFileSource = "workspace" | "daily" | "digest";
export function parseWorkspaceExtensions(value?: string): Set<string> {
const extensions = (value || "")
.split(",")
.map((item) => item.trim().toLowerCase().replace(/^\./, ""))
.filter(Boolean);
return new Set(extensions.length ? extensions : defaults);
}
export function filterWorkspacePaths(
paths: string[],
extensions: Set<string>,
): string[] {
return paths.filter((path) => {
const parts = path.split("/");
const extension = parts.at(-1)?.split(".").pop()?.toLowerCase() || "";
return (
parts.every((part) => part && !part.startsWith(".")) &&
extensions.has(extension)
);
});
}
/** Build a hierarchy while preserving the API's newest-modified-first path order. */
export function buildTree(
paths: string[],
extensions: Set<string>,
rootDirectory = "",
): TreeNode[] {
const root: TreeNode[] = [];
for (const path of filterWorkspacePaths(paths, extensions)) {
const relativePath =
rootDirectory && path.startsWith(`${rootDirectory}/`)
? path.slice(rootDirectory.length + 1)
: path;
const parts = relativePath.split("/").filter(Boolean);
let level = root;
parts.forEach((name, index) => {
const relativeNodePath = parts.slice(0, index + 1).join("/");
const nodePath = rootDirectory
? `${rootDirectory}/${relativeNodePath}`
: relativeNodePath;
let node = level.find((item) => item.name === name);
if (!node) {
node = {
name,
path: nodePath,
type: index === parts.length - 1 ? "file" : "directory",
children: [],
};
level.push(node);
}
level = node.children;
});
}
return root;
}
function cleanDirectory(value: string): string {
return value.replace(/\\/g, "/").replace(/^\/+|\/+$/g, "");
}
export function sourceDirectory(
source: WorkspaceFileSource,
config: WorkspaceDirectoryConfig,
): string {
if (source === "daily") return cleanDirectory(config.daily_dir);
if (source === "digest") return cleanDirectory(config.digest_dir);
return "";
}
export function filterPathsBySource(
paths: string[],
source: WorkspaceFileSource,
config: WorkspaceDirectoryConfig,
): string[] {
const directory = sourceDirectory(source, config);
if (!directory) return paths;
return paths.filter(
(path) => path === directory || path.startsWith(`${directory}/`),
);
}