@amistio/cli 0.1.20 → 0.1.22

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 CHANGED
@@ -9,7 +9,7 @@ npm install -g @amistio/cli
9
9
  amistio --help
10
10
  ```
11
11
 
12
- The package install only installs the `amistio` command. Repository cloning, project pairing, credential storage, sync watching, and runner execution happen only when the user explicitly runs commands such as `amistio bootstrap`, `amistio import`, `amistio pair`, `amistio sync watch`, or `amistio run --watch`. When the app copies a personal project into an organization, the CLI command syntax stays the same; create the org-scoped code and run `amistio import <code>` from the intended local checkout.
12
+ The package install only installs the `amistio` command. Repository cloning, project pairing, credential storage, sync watching, and runner execution happen only when the user explicitly runs commands such as `amistio bootstrap`, `amistio import`, `amistio pair`, `amistio sync watch`, or `amistio run --watch`. When the app copies a personal project into an organization, the CLI command syntax stays the same; create the org-scoped code and run `amistio import <code>` from the intended local checkout. Import scans repo-local project-brain docs plus recognized repo-local IDE, harness, and local AI tool memory or instruction files such as `AGENTS.md`, `.github/copilot-instructions.md`, `.cursor/rules/*.mdc`, `.windsurfrules`, and `memories/*.md`; durable Amistio memory belongs in `docs/memory/`, and global plugin or harness memory outside the repository is not scanned by default.
13
13
 
14
14
  Runner lifecycle controls in the web app, such as update, restart, and remove, apply only to the runner paired by that user unless the active organization role is an admin role. The runner API binds command polling, command status, logs, activity, and tool sessions to the local runner credential that produced them.
15
15
 
package/dist/index.js CHANGED
@@ -5635,6 +5635,8 @@ var controlPlaneRoots2 = ["architecture", "context", "decisions", "features", "m
5635
5635
  var excludedDirectoryNames = /* @__PURE__ */ new Set([".git", "node_modules", ".pnpm-store", ".next", "dist", "build", "coverage", ".cache", "cache", "tmp", "temp", "vendor"]);
5636
5636
  var excludedFileNames = /* @__PURE__ */ new Set(["docs/context/amistio-project.md", "context/amistio-project.md"]);
5637
5637
  var generatedPathSegments = /* @__PURE__ */ new Set(["generated", "__generated__", "vendor", "vendors"]);
5638
+ var rootAgentGuidanceFiles = /* @__PURE__ */ new Set(["agents.md", "claude.md", "gemini.md", "codex.md"]);
5639
+ var extensionlessInstructionFiles = /* @__PURE__ */ new Set([".cursorrules", ".windsurfrules", ".clinerules"]);
5638
5640
  var documentFolderByType = {
5639
5641
  architecture: "docs/architecture",
5640
5642
  context: "docs/context",
@@ -5674,7 +5676,7 @@ async function scanLegacyDocuments(options) {
5674
5676
  skipped.push({ repoPath, reason: "excluded" });
5675
5677
  continue;
5676
5678
  }
5677
- const contentFormat = inferContentFormatFromRepoPath(repoPath);
5679
+ const contentFormat = importableContentFormatFromRepoPath(repoPath);
5678
5680
  if (!contentFormat) {
5679
5681
  skipped.push({ repoPath, reason: "notMarkdown" });
5680
5682
  continue;
@@ -5826,6 +5828,8 @@ function isAmistioManagedDocument(content) {
5826
5828
  return /^\s*<!--[\s\S]*?amistioDocumentId\s*:/i.test(content);
5827
5829
  }
5828
5830
  function classifyLegacyDocument(repoPath, content) {
5831
+ const localMemoryDocumentType = classifyLocalMemoryDocument(repoPath, content);
5832
+ if (localMemoryDocumentType) return localMemoryDocumentType;
5829
5833
  const haystack = `${repoPath} ${inferTitle2(content, repoPath)}`.toLowerCase();
5830
5834
  if (/\b(prompt|prompts|instruction|instructions|copilot|agent|skill)\b/.test(haystack)) return "prompt";
5831
5835
  if (/\b(adr|decision|decisions|rfc)\b/.test(haystack)) return "decision";
@@ -5837,10 +5841,10 @@ function classifyLegacyDocument(repoPath, content) {
5837
5841
  return "context";
5838
5842
  }
5839
5843
  function canonicalImportPath(sourcePath, documentType, contentFormat) {
5840
- if (isCanonicalControlPlanePath(sourcePath)) {
5844
+ if (isCanonicalControlPlanePath(sourcePath) && inferContentFormatFromRepoPath(sourcePath)) {
5841
5845
  return sourcePath;
5842
5846
  }
5843
- if (isLegacyControlPlanePath(sourcePath)) {
5847
+ if (isLegacyControlPlanePath(sourcePath) && inferContentFormatFromRepoPath(sourcePath)) {
5844
5848
  return `docs/${sourcePath}`;
5845
5849
  }
5846
5850
  const baseSlug = slugFromPath(sourcePath);
@@ -5859,6 +5863,60 @@ function uniqueDestinationPath(basePath, sourcePath, usedPaths) {
5859
5863
  usedPaths.add(uniquePath);
5860
5864
  return uniquePath;
5861
5865
  }
5866
+ function importableContentFormatFromRepoPath(repoPath) {
5867
+ return inferContentFormatFromRepoPath(repoPath) ?? localMemoryImportContentFormat(repoPath);
5868
+ }
5869
+ function localMemoryImportContentFormat(repoPath) {
5870
+ const normalized = normalizeRepoPath4(repoPath);
5871
+ const lowerPath = normalized.toLowerCase();
5872
+ const basename = lowerPath.split("/").at(-1) ?? lowerPath;
5873
+ if (extensionlessInstructionFiles.has(basename)) return "markdown";
5874
+ if (/\.mdc$/i.test(normalized) && isRepoLocalToolMemoryPath(normalized)) return "markdown";
5875
+ return void 0;
5876
+ }
5877
+ function classifyLocalMemoryDocument(repoPath, content) {
5878
+ const normalized = normalizeRepoPath4(repoPath);
5879
+ if (!isRepoLocalMemoryOrInstructionPath(normalized)) return void 0;
5880
+ if (isMemoryImportPath(normalized) || hasMemoryCue(normalized, content)) {
5881
+ return "memory";
5882
+ }
5883
+ if (isInstructionImportPath(normalized)) {
5884
+ return "prompt";
5885
+ }
5886
+ return void 0;
5887
+ }
5888
+ function isRepoLocalMemoryOrInstructionPath(repoPath) {
5889
+ return isMemoryImportPath(repoPath) || isInstructionImportPath(repoPath);
5890
+ }
5891
+ function isRepoLocalToolMemoryPath(repoPath) {
5892
+ return isRepoLocalMemoryOrInstructionPath(repoPath);
5893
+ }
5894
+ function isMemoryImportPath(repoPath) {
5895
+ const lowerPath = normalizeRepoPath4(repoPath).toLowerCase();
5896
+ return /^(docs\/memory|memory|memories|\.memory|\.memories)(\/|$)/.test(lowerPath);
5897
+ }
5898
+ function isInstructionImportPath(repoPath) {
5899
+ const normalized = normalizeRepoPath4(repoPath);
5900
+ const lowerPath = normalized.toLowerCase();
5901
+ const segments = lowerPath.split("/");
5902
+ const basename = segments.at(-1) ?? lowerPath;
5903
+ if (segments.length === 1 && rootAgentGuidanceFiles.has(basename)) return true;
5904
+ if (extensionlessInstructionFiles.has(basename)) return true;
5905
+ if (lowerPath === ".github/copilot-instructions.md") return true;
5906
+ if (lowerPath.startsWith(".github/instructions/") && lowerPath.endsWith(".instructions.md")) return true;
5907
+ if (lowerPath.startsWith(".cursor/rules/") && /\.(md|mdc)$/i.test(lowerPath)) return true;
5908
+ if (lowerPath.startsWith(".windsurf/rules/") && lowerPath.endsWith(".md")) return true;
5909
+ if (lowerPath.startsWith(".cline/") && lowerPath.endsWith(".md")) return true;
5910
+ if (lowerPath.startsWith(".roo/") && lowerPath.endsWith(".md")) return true;
5911
+ if (lowerPath.startsWith(".claude/") && lowerPath.endsWith(".md")) return true;
5912
+ if (lowerPath.startsWith(".gemini/") && lowerPath.endsWith(".md")) return true;
5913
+ if (lowerPath.startsWith(".vscode/") && lowerPath.endsWith(".instructions.md")) return true;
5914
+ return false;
5915
+ }
5916
+ function hasMemoryCue(repoPath, content) {
5917
+ const haystack = `${repoPath} ${inferTitle2(content, repoPath)}`.toLowerCase();
5918
+ return /\b(memory|memories|lesson|lessons|mistake|mistakes|learning|retro|retrospective|observation|observations)\b/.test(haystack);
5919
+ }
5862
5920
  function isCanonicalControlPlanePath(repoPath) {
5863
5921
  const [firstSegment, secondSegment, thirdSegment] = normalizeRepoPath4(repoPath).split("/");
5864
5922
  return firstSegment === "docs" && Boolean(secondSegment === "html" && thirdSegment && controlPlaneRoots2.includes(thirdSegment) || secondSegment && controlPlaneRoots2.includes(secondSegment));
@@ -5884,7 +5942,7 @@ function stripFrontmatter(content) {
5884
5942
  return closingLineEnd === -1 ? "" : content.slice(closingLineEnd + 1);
5885
5943
  }
5886
5944
  function slugFromPath(repoPath) {
5887
- const withoutExtension = repoPath.replace(/\.(md|mdx|html?)$/i, "");
5945
+ const withoutExtension = repoPath.replace(/\.(md|mdx|mdc|html?)$/i, "");
5888
5946
  const slug = withoutExtension.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 90);
5889
5947
  return slug || "imported-document";
5890
5948
  }