feat(agent-forum): Add scaffolding for final agent-forum integration (#72)
- Implemented `.forum/src/install_hooks.ts` to check dependencies, safely initialize the `meta-state` orphan branch via Git plumbing commands, and install the `pre-commit` hook. - Added `.forum/src/hooks/pre-commit` bash template for Bounded Model Checking, SCIP generation, and security scanning. - Created `.forum/src/core/meta_state_manager.ts` to manage BMC validations and Merkle diffing. - Added `.forum/src/core/transitions.json` to define baseline state machine governance. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: mrteye <1945243+mrteye@users.noreply.github.com>
This commit is contained in:
parent
d4df69890f
commit
3ea3ada808
137
.forum/src/core/meta_state_manager.ts
Normal file
137
.forum/src/core/meta_state_manager.ts
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
/**
|
||||||
|
* Agent Forum v4 - Meta-State Manager
|
||||||
|
*
|
||||||
|
* This script is executed during the pre-commit hook and by tools to interact with
|
||||||
|
* the embedded data structures:
|
||||||
|
* - Validating Bounded Model Checking rules (transitions.json).
|
||||||
|
* - Writing arbitrary metadata to Git Notes.
|
||||||
|
* - Generating Git Merkle DAG Diffs for O(1) context updates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { parseArgs } from "https://deno.land/std@0.224.0/cli/parse_args.ts";
|
||||||
|
|
||||||
|
async function runCommand(
|
||||||
|
cmd: string,
|
||||||
|
args: string[],
|
||||||
|
): Promise<{ code: number; stdout: string; stderr: string }> {
|
||||||
|
const command = new Deno.Command(cmd, {
|
||||||
|
args,
|
||||||
|
stdout: "piped",
|
||||||
|
stderr: "piped",
|
||||||
|
});
|
||||||
|
const { code, stdout, stderr } = await command.output();
|
||||||
|
const decoder = new TextDecoder();
|
||||||
|
return {
|
||||||
|
code,
|
||||||
|
stdout: decoder.decode(stdout).trim(),
|
||||||
|
stderr: decoder.decode(stderr).trim(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates that the current commit meets the Bounded Model Checking rules.
|
||||||
|
* E.g., The Gatekeeper checklist must be completed before Coder changes are allowed.
|
||||||
|
*/
|
||||||
|
async function validateBoundedModelChecking() {
|
||||||
|
console.log("-> Validating Bounded Model Checking constraints...");
|
||||||
|
|
||||||
|
// We need to fetch transitions.json from the meta-state branch without checking it out
|
||||||
|
const fileCheck = await runCommand("git", [
|
||||||
|
"show",
|
||||||
|
"meta-state:transitions.json",
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (fileCheck.code !== 0) {
|
||||||
|
console.log(
|
||||||
|
"⚠️ Could not load transitions.json from meta-state branch. Skipping validation.",
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const _transitions = JSON.parse(fileCheck.stdout);
|
||||||
|
// In a real implementation, this would cross-reference the current Git Notes
|
||||||
|
// (e.g., refs/notes/gatekeeper) to see if required prerequisite tasks were signed off.
|
||||||
|
|
||||||
|
// Example pseudocode:
|
||||||
|
// const notes = await getGitNotes("gatekeeper");
|
||||||
|
// if (transitions["Coder"].requires.includes("Gatekeeper_Approval") && !notes.includes("Approved")) {
|
||||||
|
// throw new Error("Gatekeeper approval missing in Git Notes.");
|
||||||
|
// }
|
||||||
|
|
||||||
|
console.log("-> BMC validation passed (Placeholder).");
|
||||||
|
} catch (e) {
|
||||||
|
console.error("❌ Invalid transitions.json payload:", e);
|
||||||
|
Deno.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the Git Merkle DAG Diff to provide agents with precise change context.
|
||||||
|
*/
|
||||||
|
async function generateMerkleDiff() {
|
||||||
|
console.log("-> Generating Merkle DAG context diff...");
|
||||||
|
|
||||||
|
// Compare working tree against HEAD
|
||||||
|
const diffCommand = await runCommand("git", ["diff-index", "HEAD"]);
|
||||||
|
|
||||||
|
if (diffCommand.stdout === "") {
|
||||||
|
console.log(" No changes detected in working tree.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In a full implementation, we serialize this diff and possibly attach it via
|
||||||
|
// Git Notes or pass it immediately into the agent context pipeline.
|
||||||
|
// console.log(diffCommand.stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to write a JSON payload to a specific Git Note namespace.
|
||||||
|
*/
|
||||||
|
export async function writeGitNote(
|
||||||
|
namespace: string,
|
||||||
|
payload: Record<string, unknown>,
|
||||||
|
commitRef = "HEAD",
|
||||||
|
) {
|
||||||
|
const jsonString = JSON.stringify(payload);
|
||||||
|
const ref = `refs/notes/${namespace}`;
|
||||||
|
|
||||||
|
const cmd = await runCommand("git", [
|
||||||
|
"notes",
|
||||||
|
"--ref",
|
||||||
|
ref,
|
||||||
|
"add",
|
||||||
|
"-f",
|
||||||
|
"-m",
|
||||||
|
jsonString,
|
||||||
|
commitRef,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (cmd.code !== 0) {
|
||||||
|
console.error(`Failed to write Git Note to ${ref}:`, cmd.stderr);
|
||||||
|
throw new Error("Git Note write failed.");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handlePreCommit() {
|
||||||
|
await validateBoundedModelChecking();
|
||||||
|
await generateMerkleDiff();
|
||||||
|
|
||||||
|
// E.g., attaching a simple telemetry note
|
||||||
|
// await writeGitNote("telemetry", { timestamp: Date.now(), agent: "System" });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const args = parseArgs(Deno.args, {
|
||||||
|
boolean: ["pre-commit"],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (args["pre-commit"]) {
|
||||||
|
await handlePreCommit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (import.meta.main) {
|
||||||
|
await main();
|
||||||
|
}
|
||||||
20
.forum/src/core/transitions.json
Normal file
20
.forum/src/core/transitions.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"Gatekeeper": {
|
||||||
|
"requires": []
|
||||||
|
},
|
||||||
|
"Coder": {
|
||||||
|
"requires": [
|
||||||
|
"Gatekeeper_Approval"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Adversary": {
|
||||||
|
"requires": [
|
||||||
|
"Coder_Commit"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Evaluator": {
|
||||||
|
"requires": [
|
||||||
|
"Adversary_Pass"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
49
.forum/src/hooks/pre-commit
Executable file
49
.forum/src/hooks/pre-commit
Executable file
@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Agent Forum v4 - Pre-Commit Hook
|
||||||
|
#
|
||||||
|
# This hook executes Git-Native Agent Collaboration Ecosystem tasks before every commit:
|
||||||
|
# 1. Generates Semantic Code Intelligence Protocol (SCIP) & AST graphs.
|
||||||
|
# 2. Runs fast Static Analysis (Semgrep) if available.
|
||||||
|
# 3. Validates Bounded Model Checking rules via transitions.json.
|
||||||
|
# 4. Writes telemetry/reasoning payloads to Git Notes.
|
||||||
|
|
||||||
|
echo "=================================================="
|
||||||
|
echo " Agent Forum v4 - Pre-Commit Validation "
|
||||||
|
echo "=================================================="
|
||||||
|
|
||||||
|
# Exit on any failure
|
||||||
|
set -e
|
||||||
|
|
||||||
|
REPO_ROOT=$(git rev-parse --show-toplevel)
|
||||||
|
META_MANAGER="$REPO_ROOT/.forum/src/core/meta_state_manager.ts"
|
||||||
|
|
||||||
|
if [ -f "$META_MANAGER" ] && command -v deno &> /dev/null; then
|
||||||
|
echo "Running Agent Forum meta-state checks..."
|
||||||
|
|
||||||
|
# Run the meta-state manager to extract structural diffs and enforce rules.
|
||||||
|
# Note: Using run -A for Deno as it requires fs and run permissions to inspect git
|
||||||
|
if ! deno run -A "$META_MANAGER" --pre-commit; then
|
||||||
|
echo "❌ Agent Forum Bounded Model Checking failed. Commit aborted."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "⚠️ Agent Forum meta-state manager (Deno script) not found or Deno not installed. Skipping."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optional: SCIP / AST Extraction using tree-sitter
|
||||||
|
if command -v tree-sitter &> /dev/null; then
|
||||||
|
echo "-> Generating local AST structures..."
|
||||||
|
# Placeholder for actual tree-sitter invocation depending on languages used
|
||||||
|
# tree-sitter parse src/**/*.ts > .forum/temp_ast.json || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optional: Fast Security Scan
|
||||||
|
if command -v semgrep &> /dev/null; then
|
||||||
|
echo "-> Running Semgrep baseline scan..."
|
||||||
|
# Using a fast baseline check to prevent adding obvious vulnerabilities
|
||||||
|
# semgrep scan --config=auto --error || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Pre-commit validation passed."
|
||||||
|
exit 0
|
||||||
277
.forum/src/install_hooks.ts
Normal file
277
.forum/src/install_hooks.ts
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
/**
|
||||||
|
* Agent Forum v4 - Installation and Setup Script
|
||||||
|
*
|
||||||
|
* This script initializes the Git-Native Agent Collaboration Ecosystem by:
|
||||||
|
* 1. Verifying system dependencies (Deno, Git, and optionally tree-sitter/semgrep).
|
||||||
|
* 2. Initializing the `meta-state` orphan branch with the required structure.
|
||||||
|
* 3. Installing the Git pre-commit hooks.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { existsSync } from "https://deno.land/std@0.224.0/fs/exists.ts";
|
||||||
|
import { join } from "https://deno.land/std@0.224.0/path/mod.ts";
|
||||||
|
|
||||||
|
const CWD = Deno.cwd();
|
||||||
|
const GIT_DIR = join(CWD, ".git");
|
||||||
|
const HOOKS_DIR = join(GIT_DIR, "hooks");
|
||||||
|
const FORUM_HOOKS_DIR = join(CWD, ".forum", "src", "hooks");
|
||||||
|
|
||||||
|
async function runCommand(
|
||||||
|
cmd: string,
|
||||||
|
args: string[],
|
||||||
|
): Promise<{ code: number; stdout: string; stderr: string }> {
|
||||||
|
try {
|
||||||
|
const command = new Deno.Command(cmd, {
|
||||||
|
args,
|
||||||
|
stdout: "piped",
|
||||||
|
stderr: "piped",
|
||||||
|
});
|
||||||
|
const { code, stdout, stderr } = await command.output();
|
||||||
|
const decoder = new TextDecoder();
|
||||||
|
return {
|
||||||
|
code,
|
||||||
|
stdout: decoder.decode(stdout).trim(),
|
||||||
|
stderr: decoder.decode(stderr).trim(),
|
||||||
|
};
|
||||||
|
} catch (e: any) {
|
||||||
|
return {
|
||||||
|
code: -1,
|
||||||
|
stdout: "",
|
||||||
|
stderr: e.message || String(e),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkDependencies() {
|
||||||
|
console.log("Checking dependencies...");
|
||||||
|
|
||||||
|
// Git
|
||||||
|
const gitCheck = await runCommand("git", ["--version"]);
|
||||||
|
if (gitCheck.code !== 0) {
|
||||||
|
console.error("❌ Git is not installed or not in PATH.");
|
||||||
|
Deno.exit(1);
|
||||||
|
}
|
||||||
|
console.log(`✅ ${gitCheck.stdout}`);
|
||||||
|
|
||||||
|
// Deno
|
||||||
|
const denoCheck = await runCommand("deno", ["--version"]);
|
||||||
|
if (denoCheck.code !== 0) {
|
||||||
|
console.error("❌ Deno is not installed or not in PATH.");
|
||||||
|
Deno.exit(1);
|
||||||
|
}
|
||||||
|
console.log(`✅ Deno installed`);
|
||||||
|
|
||||||
|
// Optional: Tree-sitter
|
||||||
|
const treeSitterCheck = await runCommand("tree-sitter", ["--version"]);
|
||||||
|
if (treeSitterCheck.code === 0) {
|
||||||
|
console.log(`✅ tree-sitter found: ${treeSitterCheck.stdout}`);
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
"⚠️ tree-sitter not found. SCIP/AST generation may be limited.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional: Semgrep
|
||||||
|
const semgrepCheck = await runCommand("semgrep", ["--version"]);
|
||||||
|
if (semgrepCheck.code === 0) {
|
||||||
|
console.log(`✅ semgrep found: ${semgrepCheck.stdout}`);
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
"⚠️ semgrep not found. Security analysis payloads may be skipped.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function initializeMetaStateBranch() {
|
||||||
|
console.log("\nInitializing 'meta-state' orphan branch...");
|
||||||
|
|
||||||
|
// Check if branch exists
|
||||||
|
const checkBranch = await runCommand("git", [
|
||||||
|
"show-ref",
|
||||||
|
"--verify",
|
||||||
|
"refs/heads/meta-state",
|
||||||
|
]);
|
||||||
|
if (checkBranch.code === 0) {
|
||||||
|
console.log(
|
||||||
|
"✅ 'meta-state' branch already exists. Preserving existing data.",
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Creating 'meta-state' orphan branch...");
|
||||||
|
|
||||||
|
// Save current branch name (not strictly needed since we use plumbing, but kept for context if needed later)
|
||||||
|
const currentBranchRes = await runCommand("git", [
|
||||||
|
"rev-parse",
|
||||||
|
"--abbrev-ref",
|
||||||
|
"HEAD",
|
||||||
|
]);
|
||||||
|
const _currentBranch = currentBranchRes.stdout;
|
||||||
|
|
||||||
|
// Create temporary directory for meta-state tree
|
||||||
|
const tempDir = await Deno.makeTempDir();
|
||||||
|
|
||||||
|
// Create structure
|
||||||
|
const dirs = ["tasks", "ontologies", "vectors"];
|
||||||
|
for (const d of dirs) {
|
||||||
|
await Deno.mkdir(join(tempDir, d), { recursive: true });
|
||||||
|
// Add a .gitkeep so git tracks the directory
|
||||||
|
await Deno.writeTextFile(join(tempDir, d, ".gitkeep"), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Baseline transitions.json
|
||||||
|
const defaultTransitions = {
|
||||||
|
"Gatekeeper": { "requires": [] },
|
||||||
|
"Coder": { "requires": ["Gatekeeper_Approval"] },
|
||||||
|
"Adversary": { "requires": ["Coder_Commit"] },
|
||||||
|
};
|
||||||
|
await Deno.writeTextFile(
|
||||||
|
join(tempDir, "transitions.json"),
|
||||||
|
JSON.stringify(defaultTransitions, null, 2),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Also copy from .forum/src/core/transitions.json if it exists
|
||||||
|
const coreTransitions = join(
|
||||||
|
CWD,
|
||||||
|
".forum",
|
||||||
|
"src",
|
||||||
|
"core",
|
||||||
|
"transitions.json",
|
||||||
|
);
|
||||||
|
if (existsSync(coreTransitions)) {
|
||||||
|
await Deno.copyFile(coreTransitions, join(tempDir, "transitions.json"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to create a commit on the orphan branch using git plumbing commands
|
||||||
|
// to avoid changing the working directory files
|
||||||
|
|
||||||
|
console.log("Running git plumbing commands to build meta-state tree...");
|
||||||
|
|
||||||
|
// 1. Create a temporary index file isolated from the main index
|
||||||
|
const env = {
|
||||||
|
...Deno.env.toObject(),
|
||||||
|
GIT_INDEX_FILE: join(GIT_DIR, "index_meta_state"),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ensure index is clean
|
||||||
|
try {
|
||||||
|
await Deno.remove(env.GIT_INDEX_FILE);
|
||||||
|
} catch (_e) {
|
||||||
|
// Ignore if doesn't exist
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Add files to the temporary index using git hash-object and update-index
|
||||||
|
for (const d of dirs) {
|
||||||
|
const keepPath = join(tempDir, d, ".gitkeep");
|
||||||
|
const hashCmd = await runCommand("git", ["hash-object", "-w", keepPath]);
|
||||||
|
const blobId = hashCmd.stdout;
|
||||||
|
await new Deno.Command("git", {
|
||||||
|
args: [
|
||||||
|
"update-index",
|
||||||
|
"--add",
|
||||||
|
"--cacheinfo",
|
||||||
|
`100644,${blobId},${d}/.gitkeep`,
|
||||||
|
],
|
||||||
|
env,
|
||||||
|
}).output();
|
||||||
|
}
|
||||||
|
|
||||||
|
const transPath = join(tempDir, "transitions.json");
|
||||||
|
const transHashCmd = await runCommand("git", [
|
||||||
|
"hash-object",
|
||||||
|
"-w",
|
||||||
|
transPath,
|
||||||
|
]);
|
||||||
|
const transBlobId = transHashCmd.stdout;
|
||||||
|
await new Deno.Command("git", {
|
||||||
|
args: [
|
||||||
|
"update-index",
|
||||||
|
"--add",
|
||||||
|
"--cacheinfo",
|
||||||
|
`100644,${transBlobId},transitions.json`,
|
||||||
|
],
|
||||||
|
env,
|
||||||
|
}).output();
|
||||||
|
|
||||||
|
// 3. Write tree
|
||||||
|
const writeTreeCmd = await new Deno.Command("git", {
|
||||||
|
args: ["write-tree"],
|
||||||
|
env,
|
||||||
|
stdout: "piped",
|
||||||
|
}).output();
|
||||||
|
const treeId = new TextDecoder().decode(writeTreeCmd.stdout).trim();
|
||||||
|
|
||||||
|
// 4. Commit tree as an orphan commit
|
||||||
|
const commitCmd = await runCommand("git", [
|
||||||
|
"commit-tree",
|
||||||
|
treeId,
|
||||||
|
"-m",
|
||||||
|
"chore: initialize meta-state branch structure",
|
||||||
|
]);
|
||||||
|
const commitId = commitCmd.stdout;
|
||||||
|
|
||||||
|
// 5. Update ref to create the branch
|
||||||
|
await runCommand("git", ["update-ref", "refs/heads/meta-state", commitId]);
|
||||||
|
|
||||||
|
// Clean up index file
|
||||||
|
try {
|
||||||
|
await Deno.remove(env.GIT_INDEX_FILE);
|
||||||
|
} catch (_e) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
"✅ 'meta-state' branch initialized successfully without modifying working tree.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function installHooks() {
|
||||||
|
console.log("\nInstalling Git Hooks...");
|
||||||
|
|
||||||
|
if (!existsSync(GIT_DIR)) {
|
||||||
|
console.error(
|
||||||
|
"❌ .git directory not found. Must be run from the root of a git repository.",
|
||||||
|
);
|
||||||
|
Deno.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const preCommitSource = join(FORUM_HOOKS_DIR, "pre-commit");
|
||||||
|
const preCommitTarget = join(HOOKS_DIR, "pre-commit");
|
||||||
|
|
||||||
|
if (!existsSync(preCommitSource)) {
|
||||||
|
console.error(`❌ Hook template not found at ${preCommitSource}`);
|
||||||
|
Deno.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existsSync(preCommitTarget)) {
|
||||||
|
console.log("⚠️ An existing pre-commit hook was found.");
|
||||||
|
console.log("Moving existing hook to pre-commit.backup...");
|
||||||
|
await Deno.rename(preCommitTarget, join(HOOKS_DIR, "pre-commit.backup"));
|
||||||
|
}
|
||||||
|
|
||||||
|
await Deno.copyFile(preCommitSource, preCommitTarget);
|
||||||
|
|
||||||
|
// Make it executable (chmod +x)
|
||||||
|
if (Deno.build.os !== "windows") {
|
||||||
|
await runCommand("chmod", ["+x", preCommitTarget]);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("✅ pre-commit hook installed successfully.");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
console.log("==================================================");
|
||||||
|
console.log(" Agent Forum v4 - Initialization Script ");
|
||||||
|
console.log("==================================================\n");
|
||||||
|
|
||||||
|
await checkDependencies();
|
||||||
|
await installHooks();
|
||||||
|
await initializeMetaStateBranch();
|
||||||
|
|
||||||
|
console.log("\n==================================================");
|
||||||
|
console.log("🎉 Setup complete! The Agent Forum ecosystem is ready.");
|
||||||
|
console.log("==================================================");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (import.meta.main) {
|
||||||
|
await main();
|
||||||
|
}
|
||||||
2
deno.lock
generated
2
deno.lock
generated
@ -661,10 +661,12 @@
|
|||||||
"https://deno.land/std@0.224.0/assert/mod.ts": "48b8cb8a619ea0b7958ad7ee9376500fe902284bb36f0e32c598c3dc34cbd6f3",
|
"https://deno.land/std@0.224.0/assert/mod.ts": "48b8cb8a619ea0b7958ad7ee9376500fe902284bb36f0e32c598c3dc34cbd6f3",
|
||||||
"https://deno.land/std@0.224.0/assert/unimplemented.ts": "8c55a5793e9147b4f1ef68cd66496b7d5ba7a9e7ca30c6da070c1a58da723d73",
|
"https://deno.land/std@0.224.0/assert/unimplemented.ts": "8c55a5793e9147b4f1ef68cd66496b7d5ba7a9e7ca30c6da070c1a58da723d73",
|
||||||
"https://deno.land/std@0.224.0/assert/unreachable.ts": "5ae3dbf63ef988615b93eb08d395dda771c96546565f9e521ed86f6510c29e19",
|
"https://deno.land/std@0.224.0/assert/unreachable.ts": "5ae3dbf63ef988615b93eb08d395dda771c96546565f9e521ed86f6510c29e19",
|
||||||
|
"https://deno.land/std@0.224.0/cli/parse_args.ts": "5250832fb7c544d9111e8a41ad272c016f5a53f975ef84d5a9fe5fcb70566ece",
|
||||||
"https://deno.land/std@0.224.0/fmt/colors.ts": "508563c0659dd7198ba4bbf87e97f654af3c34eb56ba790260f252ad8012e1c5",
|
"https://deno.land/std@0.224.0/fmt/colors.ts": "508563c0659dd7198ba4bbf87e97f654af3c34eb56ba790260f252ad8012e1c5",
|
||||||
"https://deno.land/std@0.224.0/front_matter/_formats.ts": "9a8ac1524f93b3ae093bd66864a49fc0088037920c6d60863da136d10f92e04d",
|
"https://deno.land/std@0.224.0/front_matter/_formats.ts": "9a8ac1524f93b3ae093bd66864a49fc0088037920c6d60863da136d10f92e04d",
|
||||||
"https://deno.land/std@0.224.0/front_matter/create_extractor.ts": "642e6e55cd07864b7c8068f88d271290d5d0a13d979ad335e10a7f52046b1f80",
|
"https://deno.land/std@0.224.0/front_matter/create_extractor.ts": "642e6e55cd07864b7c8068f88d271290d5d0a13d979ad335e10a7f52046b1f80",
|
||||||
"https://deno.land/std@0.224.0/front_matter/yaml.ts": "103b8338bec480c6b7a7e245cf6bda72682eb78ed2231c799a4526d52cb6888a",
|
"https://deno.land/std@0.224.0/front_matter/yaml.ts": "103b8338bec480c6b7a7e245cf6bda72682eb78ed2231c799a4526d52cb6888a",
|
||||||
|
"https://deno.land/std@0.224.0/fs/exists.ts": "3d38cb7dcbca3cf313be343a7b8af18a87bddb4b5ca1bd2314be12d06533b50f",
|
||||||
"https://deno.land/std@0.224.0/internal/diff.ts": "6234a4b493ebe65dc67a18a0eb97ef683626a1166a1906232ce186ae9f65f4e6",
|
"https://deno.land/std@0.224.0/internal/diff.ts": "6234a4b493ebe65dc67a18a0eb97ef683626a1166a1906232ce186ae9f65f4e6",
|
||||||
"https://deno.land/std@0.224.0/internal/format.ts": "0a98ee226fd3d43450245b1844b47003419d34d210fa989900861c79820d21c2",
|
"https://deno.land/std@0.224.0/internal/format.ts": "0a98ee226fd3d43450245b1844b47003419d34d210fa989900861c79820d21c2",
|
||||||
"https://deno.land/std@0.224.0/internal/mod.ts": "534125398c8e7426183e12dc255bb635d94e06d0f93c60a297723abe69d3b22e",
|
"https://deno.land/std@0.224.0/internal/mod.ts": "534125398c8e7426183e12dc255bb635d94e06d0f93c60a297723abe69d3b22e",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user