diff --git a/API.md b/API.md
index fb1a67b..7244f91 100644
--- a/API.md
+++ b/API.md
@@ -22,7 +22,7 @@ Add that to your `~/.bashrc` or `~/.zshrc` file to make it permanent. Be sure to
In a new directory, run:
-`projen new ovosskill --from "@mikejgray/ovos-skill-projen@latest"`
+`npx projen new ovosskill --from "@mikejgray/ovos-skill-projen@latest"`
**NOTE**: This repo is not yet available on NPM. Please add the following to your `~/.npmrc` file (create one if it doesn't exist), with [a GitHub token that has packages:read permissions](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-npm-registry):
@@ -52,6 +52,26 @@ Example:
After editing `.projenrc.json`, run `pj` to regenerate the project files. This can automatically keep your project up to date with the latest changes, including managing your `setup.py` file.
+## Create a new PHAL plugin template
+
+In a new directory, run:
+
+`npx projen new ovosphal --from "@mikejgray/ovos-skill-projen@latest"`
+
+The instructions are the same as for creating a new skill template, except that you have an additional option to set the PHAL plugin as admin or not. The default is `false`, indicating that the PHAL plugin will not run as root.
+
+**NOTE:** If you do set the PHAL plugin to `admin` and thus run as root, you will also need to update your OVOS config to explicitly allow your root plugins. This is a security risk and should only be done if you understand the implications. For more information about Admin PHAL, [see the OVOS technical manual](https://openvoiceos.github.io/ovos-technical-manual/PHAL/#admin-phal).
+
+Example OVOS config:
+
+```json
+{
+ "PHAL": {
+ "admin": "ovos-phal-plugin-helloworld": {"enabled": true}
+ }
+}
+```
+
### setup.py ownership
Note that projen takes ownership of the `setup.py` file, and the expectation is that manual edits are not allowed. If you need to make changes to the `setup.py` file, you should do so by editing `.projenrc.json` and running `pj` to regenerate the file.
@@ -91,68 +111,69 @@ If your skill code is not in `__init__.py` in the repository root, the retrofit
## Structs
-### OVOSSkillProjectOptions
+### OVOSPHALProjectOptions
-#### Initializer
+#### Initializer
```typescript
-import { OVOSSkillProjectOptions } from '@mikejgray/ovos-skill-projen'
+import { OVOSPHALProjectOptions } from '@mikejgray/ovos-skill-projen'
-const oVOSSkillProjectOptions: OVOSSkillProjectOptions = { ... }
+const oVOSPHALProjectOptions: OVOSPHALProjectOptions = { ... }
```
#### Properties
| **Name** | **Type** | **Description** |
| --- | --- | --- |
-| name
| string
| This is the name of your project. |
-| commitGenerated
| boolean
| Whether to commit the managed files by default. |
-| gitIgnoreOptions
| projen.IgnoreFileOptions
| Configuration options for .gitignore file. |
-| gitOptions
| projen.GitOptions
| Configuration options for git. |
-| logging
| projen.LoggerOptions
| Configure logging options such as verbosity. |
-| outdir
| string
| The root directory of the project. |
-| parent
| projen.Project
| The parent project, if this project is part of a bigger project. |
-| projenCommand
| string
| The shell command to use in order to run the projen CLI. |
-| projenrcJson
| boolean
| Generate (once) .projenrc.json (in JSON). Set to `false` in order to disable .projenrc.json generation. |
-| projenrcJsonOptions
| projen.ProjenrcJsonOptions
| Options for .projenrc.json. |
-| renovatebot
| boolean
| Use renovatebot to handle dependency upgrades. |
-| renovatebotOptions
| projen.RenovatebotOptions
| Options for renovatebot. |
-| autoApproveOptions
| projen.github.AutoApproveOptions
| Enable and configure the 'auto approve' workflow. |
-| autoMerge
| boolean
| Enable automatic merging on GitHub. |
-| autoMergeOptions
| projen.github.AutoMergeOptions
| Configure options for automatic merging on GitHub. |
-| clobber
| boolean
| Add a `clobber` task which resets the repo to origin. |
-| devContainer
| boolean
| Add a VSCode development environment (used for GitHub Codespaces). |
-| github
| boolean
| Enable GitHub integration. |
-| githubOptions
| projen.github.GitHubOptions
| Options for GitHub integration. |
-| gitpod
| boolean
| Add a Gitpod development environment. |
-| mergify
| boolean
| Whether mergify should be enabled on this repository or not. |
-| mergifyOptions
| projen.github.MergifyOptions
| Options for mergify. |
-| projectType
| projen.ProjectType
| Which type of project this is (library/app). |
-| projenCredentials
| projen.github.GithubCredentials
| Choose a method of providing GitHub API access for projen workflows. |
-| projenTokenSecret
| string
| The name of a secret which includes a GitHub Personal Access Token to be used by projen workflows. |
-| readme
| projen.SampleReadmeProps
| The README setup. |
-| stale
| boolean
| Auto-close of stale issues and pull request. |
-| staleOptions
| projen.github.StaleOptions
| Auto-close stale issues and pull requests. |
-| vscode
| boolean
| Enable VSCode integration. |
-| author
| string
| The name of the skill's author. |
-| authorAddress
| string
| The email address of the skill's author. |
-| authorHandle
| string
| The GitHub handle of the skill's author. |
-| condenseLocaleFolders
| boolean
| Restructure locale folders to be more OVOS-like? |
-| githubWorkflows
| boolean
| Add Github Actions workflows? |
-| license
| string
| The license of the skill. |
-| packageDir
| string
| The name of the directory containing the skill's code. |
-| pypiName
| string
| The name of the skill's PyPi package. |
-| repositoryUrl
| string
| The URL of the skill's GitHub repository. |
-| retrofit
| boolean
| Retrofit an existing Mycroft skill to OVOS? |
-| sampleCode
| boolean
| Include sample code? |
-| skillClass
| string
| The name of the skill class. |
-| skillDescription
| string
| The description of the skill. |
-| skillKeywords
| string
| Keywords for your skill package. |
-| skillLicenseTest
| boolean
| Include a test to check that the skill's license is FOSS? |
-
----
-
-##### `name`Required
+| name
| string
| This is the name of your project. |
+| commitGenerated
| boolean
| Whether to commit the managed files by default. |
+| gitIgnoreOptions
| projen.IgnoreFileOptions
| Configuration options for .gitignore file. |
+| gitOptions
| projen.GitOptions
| Configuration options for git. |
+| logging
| projen.LoggerOptions
| Configure logging options such as verbosity. |
+| outdir
| string
| The root directory of the project. |
+| parent
| projen.Project
| The parent project, if this project is part of a bigger project. |
+| projenCommand
| string
| The shell command to use in order to run the projen CLI. |
+| projenrcJson
| boolean
| Generate (once) .projenrc.json (in JSON). Set to `false` in order to disable .projenrc.json generation. |
+| projenrcJsonOptions
| projen.ProjenrcJsonOptions
| Options for .projenrc.json. |
+| renovatebot
| boolean
| Use renovatebot to handle dependency upgrades. |
+| renovatebotOptions
| projen.RenovatebotOptions
| Options for renovatebot. |
+| autoApproveOptions
| projen.github.AutoApproveOptions
| Enable and configure the 'auto approve' workflow. |
+| autoMerge
| boolean
| Enable automatic merging on GitHub. |
+| autoMergeOptions
| projen.github.AutoMergeOptions
| Configure options for automatic merging on GitHub. |
+| clobber
| boolean
| Add a `clobber` task which resets the repo to origin. |
+| devContainer
| boolean
| Add a VSCode development environment (used for GitHub Codespaces). |
+| github
| boolean
| Enable GitHub integration. |
+| githubOptions
| projen.github.GitHubOptions
| Options for GitHub integration. |
+| gitpod
| boolean
| Add a Gitpod development environment. |
+| mergify
| boolean
| Whether mergify should be enabled on this repository or not. |
+| mergifyOptions
| projen.github.MergifyOptions
| Options for mergify. |
+| projectType
| projen.ProjectType
| Which type of project this is (library/app). |
+| projenCredentials
| projen.github.GithubCredentials
| Choose a method of providing GitHub API access for projen workflows. |
+| projenTokenSecret
| string
| The name of a secret which includes a GitHub Personal Access Token to be used by projen workflows. |
+| readme
| projen.SampleReadmeProps
| The README setup. |
+| stale
| boolean
| Auto-close of stale issues and pull request. |
+| staleOptions
| projen.github.StaleOptions
| Auto-close stale issues and pull requests. |
+| vscode
| boolean
| Enable VSCode integration. |
+| author
| string
| The name of the skill's author. |
+| authorAddress
| string
| The email address of the skill's author. |
+| authorHandle
| string
| The GitHub handle of the skill's author. |
+| condenseLocaleFolders
| boolean
| Restructure locale folders to be more OVOS-like? |
+| githubWorkflows
| boolean
| Add Github Actions workflows? |
+| license
| string
| The license of the skill. |
+| packageDir
| string
| The name of the directory containing the skill's code. |
+| pypiName
| string
| The name of the skill's PyPi package. |
+| repositoryUrl
| string
| The URL of the skill's GitHub repository. |
+| retrofit
| boolean
| Retrofit an existing Mycroft skill to OVOS? |
+| sampleCode
| boolean
| Include sample code? |
+| skillClass
| string
| The name of the skill class. |
+| skillDescription
| string
| The description of the skill. |
+| skillKeywords
| string
| Keywords for your skill package. |
+| skillLicenseTest
| boolean
| Include a test to check that the skill's license is FOSS? |
+| admin
| boolean
| Is this an admin PHAL plugin? |
+
+---
+
+##### `name`Required
```typescript
public readonly name: string;
@@ -165,7 +186,7 @@ This is the name of your project.
---
-##### `commitGenerated`Optional
+##### `commitGenerated`Optional
```typescript
public readonly commitGenerated: boolean;
@@ -178,7 +199,7 @@ Whether to commit the managed files by default.
---
-##### `gitIgnoreOptions`Optional
+##### `gitIgnoreOptions`Optional
```typescript
public readonly gitIgnoreOptions: IgnoreFileOptions;
@@ -190,7 +211,7 @@ Configuration options for .gitignore file.
---
-##### `gitOptions`Optional
+##### `gitOptions`Optional
```typescript
public readonly gitOptions: GitOptions;
@@ -202,7 +223,7 @@ Configuration options for git.
---
-##### `logging`Optional
+##### `logging`Optional
```typescript
public readonly logging: LoggerOptions;
@@ -215,7 +236,7 @@ Configure logging options such as verbosity.
---
-##### `outdir`Optional
+##### `outdir`Optional
```typescript
public readonly outdir: string;
@@ -234,7 +255,7 @@ sub-projects.
---
-##### `parent`Optional
+##### `parent`Optional
```typescript
public readonly parent: Project;
@@ -246,7 +267,7 @@ The parent project, if this project is part of a bigger project.
---
-##### `projenCommand`Optional
+##### `projenCommand`Optional
```typescript
public readonly projenCommand: string;
@@ -261,7 +282,7 @@ Can be used to customize in special environments.
---
-##### `projenrcJson`Optional
+##### `projenrcJson`Optional
```typescript
public readonly projenrcJson: boolean;
@@ -274,7 +295,7 @@ Generate (once) .projenrc.json (in JSON). Set to `false` in order to disable .pr
---
-##### `projenrcJsonOptions`Optional
+##### `projenrcJsonOptions`Optional
```typescript
public readonly projenrcJsonOptions: ProjenrcJsonOptions;
@@ -287,7 +308,7 @@ Options for .projenrc.json.
---
-##### `renovatebot`Optional
+##### `renovatebot`Optional
```typescript
public readonly renovatebot: boolean;
@@ -300,7 +321,7 @@ Use renovatebot to handle dependency upgrades.
---
-##### `renovatebotOptions`Optional
+##### `renovatebotOptions`Optional
```typescript
public readonly renovatebotOptions: RenovatebotOptions;
@@ -313,7 +334,7 @@ Options for renovatebot.
---
-##### `autoApproveOptions`Optional
+##### `autoApproveOptions`Optional
```typescript
public readonly autoApproveOptions: AutoApproveOptions;
@@ -326,7 +347,7 @@ Enable and configure the 'auto approve' workflow.
---
-##### `autoMerge`Optional
+##### `autoMerge`Optional
```typescript
public readonly autoMerge: boolean;
@@ -342,7 +363,7 @@ is set to false.
---
-##### `autoMergeOptions`Optional
+##### `autoMergeOptions`Optional
```typescript
public readonly autoMergeOptions: AutoMergeOptions;
@@ -358,7 +379,7 @@ Has no effect if
---
-##### `clobber`Optional
+##### `clobber`Optional
```typescript
public readonly clobber: boolean;
@@ -371,7 +392,7 @@ Add a `clobber` task which resets the repo to origin.
---
-##### `devContainer`Optional
+##### `devContainer`Optional
```typescript
public readonly devContainer: boolean;
@@ -384,7 +405,7 @@ Add a VSCode development environment (used for GitHub Codespaces).
---
-##### `github`Optional
+##### `github`Optional
```typescript
public readonly github: boolean;
@@ -399,7 +420,7 @@ Enabled by default for root projects. Disabled for non-root projects.
---
-##### `githubOptions`Optional
+##### `githubOptions`Optional
```typescript
public readonly githubOptions: GitHubOptions;
@@ -412,7 +433,7 @@ Options for GitHub integration.
---
-##### `gitpod`Optional
+##### `gitpod`Optional
```typescript
public readonly gitpod: boolean;
@@ -425,7 +446,7 @@ Add a Gitpod development environment.
---
-##### ~~`mergify`~~Optional
+##### ~~`mergify`~~Optional
- *Deprecated:* use `githubOptions.mergify` instead
@@ -440,7 +461,7 @@ Whether mergify should be enabled on this repository or not.
---
-##### ~~`mergifyOptions`~~Optional
+##### ~~`mergifyOptions`~~Optional
- *Deprecated:* use `githubOptions.mergifyOptions` instead
@@ -455,7 +476,7 @@ Options for mergify.
---
-##### ~~`projectType`~~Optional
+##### ~~`projectType`~~Optional
- *Deprecated:* no longer supported at the base project level
@@ -470,7 +491,7 @@ Which type of project this is (library/app).
---
-##### `projenCredentials`Optional
+##### `projenCredentials`Optional
```typescript
public readonly projenCredentials: GithubCredentials;
@@ -483,7 +504,7 @@ Choose a method of providing GitHub API access for projen workflows.
---
-##### ~~`projenTokenSecret`~~Optional
+##### ~~`projenTokenSecret`~~Optional
- *Deprecated:* use `projenCredentials`
@@ -501,7 +522,7 @@ and `packages` scope.
---
-##### `readme`Optional
+##### `readme`Optional
```typescript
public readonly readme: SampleReadmeProps;
@@ -521,7 +542,7 @@ The README setup.
```
-##### `stale`Optional
+##### `stale`Optional
```typescript
public readonly stale: boolean;
@@ -536,7 +557,7 @@ See `staleOptions` for options.
---
-##### `staleOptions`Optional
+##### `staleOptions`Optional
```typescript
public readonly staleOptions: StaleOptions;
@@ -551,7 +572,7 @@ To disable set `stale` to `false`.
---
-##### `vscode`Optional
+##### `vscode`Optional
```typescript
public readonly vscode: boolean;
@@ -566,7 +587,7 @@ Enabled by default for root projects. Disabled for non-root projects.
---
-##### `author`Optional
+##### `author`Optional
```typescript
public readonly author: string;
@@ -586,7 +607,7 @@ The name of the skill's author.
```
-##### `authorAddress`Optional
+##### `authorAddress`Optional
```typescript
public readonly authorAddress: string;
@@ -606,7 +627,7 @@ The email address of the skill's author.
```
-##### `authorHandle`Optional
+##### `authorHandle`Optional
```typescript
public readonly authorHandle: string;
@@ -626,7 +647,7 @@ The GitHub handle of the skill's author.
```
-##### `condenseLocaleFolders`Optional
+##### `condenseLocaleFolders`Optional
```typescript
public readonly condenseLocaleFolders: boolean;
@@ -639,7 +660,7 @@ Restructure locale folders to be more OVOS-like?
---
-##### `githubWorkflows`Optional
+##### `githubWorkflows`Optional
```typescript
public readonly githubWorkflows: boolean;
@@ -652,7 +673,7 @@ Add Github Actions workflows?
---
-##### `license`Optional
+##### `license`Optional
```typescript
public readonly license: string;
@@ -672,7 +693,7 @@ MIT
```
-##### `packageDir`Optional
+##### `packageDir`Optional
```typescript
public readonly packageDir: string;
@@ -692,7 +713,7 @@ The name of the directory containing the skill's code.
```
-##### `pypiName`Optional
+##### `pypiName`Optional
```typescript
public readonly pypiName: string;
@@ -711,7 +732,7 @@ ovos-hello-world-skill
```
-##### `repositoryUrl`Optional
+##### `repositoryUrl`Optional
```typescript
public readonly repositoryUrl: string;
@@ -731,7 +752,7 @@ The URL of the skill's GitHub repository.
```
-##### `retrofit`Optional
+##### `retrofit`Optional
```typescript
public readonly retrofit: boolean;
@@ -744,7 +765,7 @@ Retrofit an existing Mycroft skill to OVOS?
---
-##### `sampleCode`Optional
+##### `sampleCode`Optional
```typescript
public readonly sampleCode: boolean;
@@ -757,7 +778,7 @@ Include sample code?
---
-##### `skillClass`Optional
+##### `skillClass`Optional
```typescript
public readonly skillClass: string;
@@ -776,7 +797,7 @@ HelloWorldSkill
```
-##### `skillDescription`Optional
+##### `skillDescription`Optional
```typescript
public readonly skillDescription: string;
@@ -798,7 +819,7 @@ Used in setup.py.
```
-##### `skillKeywords`Optional
+##### `skillKeywords`Optional
```typescript
public readonly skillKeywords: string;
@@ -811,7 +832,7 @@ Keywords for your skill package.
---
-##### `skillLicenseTest`Optional
+##### `skillLicenseTest`Optional
```typescript
public readonly skillLicenseTest: boolean;
@@ -824,7 +845,1517 @@ Include a test to check that the skill's license is FOSS?
---
-## Classes
+##### `admin`Optional
+
+```typescript
+public readonly admin: boolean;
+```
+
+- *Type:* boolean
+- *Default:* false
+
+Is this an admin PHAL plugin?
+
+---
+
+### OVOSSkillProjectOptions
+
+#### Initializer
+
+```typescript
+import { OVOSSkillProjectOptions } from '@mikejgray/ovos-skill-projen'
+
+const oVOSSkillProjectOptions: OVOSSkillProjectOptions = { ... }
+```
+
+#### Properties
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| name
| string
| This is the name of your project. |
+| commitGenerated
| boolean
| Whether to commit the managed files by default. |
+| gitIgnoreOptions
| projen.IgnoreFileOptions
| Configuration options for .gitignore file. |
+| gitOptions
| projen.GitOptions
| Configuration options for git. |
+| logging
| projen.LoggerOptions
| Configure logging options such as verbosity. |
+| outdir
| string
| The root directory of the project. |
+| parent
| projen.Project
| The parent project, if this project is part of a bigger project. |
+| projenCommand
| string
| The shell command to use in order to run the projen CLI. |
+| projenrcJson
| boolean
| Generate (once) .projenrc.json (in JSON). Set to `false` in order to disable .projenrc.json generation. |
+| projenrcJsonOptions
| projen.ProjenrcJsonOptions
| Options for .projenrc.json. |
+| renovatebot
| boolean
| Use renovatebot to handle dependency upgrades. |
+| renovatebotOptions
| projen.RenovatebotOptions
| Options for renovatebot. |
+| autoApproveOptions
| projen.github.AutoApproveOptions
| Enable and configure the 'auto approve' workflow. |
+| autoMerge
| boolean
| Enable automatic merging on GitHub. |
+| autoMergeOptions
| projen.github.AutoMergeOptions
| Configure options for automatic merging on GitHub. |
+| clobber
| boolean
| Add a `clobber` task which resets the repo to origin. |
+| devContainer
| boolean
| Add a VSCode development environment (used for GitHub Codespaces). |
+| github
| boolean
| Enable GitHub integration. |
+| githubOptions
| projen.github.GitHubOptions
| Options for GitHub integration. |
+| gitpod
| boolean
| Add a Gitpod development environment. |
+| mergify
| boolean
| Whether mergify should be enabled on this repository or not. |
+| mergifyOptions
| projen.github.MergifyOptions
| Options for mergify. |
+| projectType
| projen.ProjectType
| Which type of project this is (library/app). |
+| projenCredentials
| projen.github.GithubCredentials
| Choose a method of providing GitHub API access for projen workflows. |
+| projenTokenSecret
| string
| The name of a secret which includes a GitHub Personal Access Token to be used by projen workflows. |
+| readme
| projen.SampleReadmeProps
| The README setup. |
+| stale
| boolean
| Auto-close of stale issues and pull request. |
+| staleOptions
| projen.github.StaleOptions
| Auto-close stale issues and pull requests. |
+| vscode
| boolean
| Enable VSCode integration. |
+| author
| string
| The name of the skill's author. |
+| authorAddress
| string
| The email address of the skill's author. |
+| authorHandle
| string
| The GitHub handle of the skill's author. |
+| condenseLocaleFolders
| boolean
| Restructure locale folders to be more OVOS-like? |
+| githubWorkflows
| boolean
| Add Github Actions workflows? |
+| license
| string
| The license of the skill. |
+| packageDir
| string
| The name of the directory containing the skill's code. |
+| pypiName
| string
| The name of the skill's PyPi package. |
+| repositoryUrl
| string
| The URL of the skill's GitHub repository. |
+| retrofit
| boolean
| Retrofit an existing Mycroft skill to OVOS? |
+| sampleCode
| boolean
| Include sample code? |
+| skillClass
| string
| The name of the skill class. |
+| skillDescription
| string
| The description of the skill. |
+| skillKeywords
| string
| Keywords for your skill package. |
+| skillLicenseTest
| boolean
| Include a test to check that the skill's license is FOSS? |
+
+---
+
+##### `name`Required
+
+```typescript
+public readonly name: string;
+```
+
+- *Type:* string
+- *Default:* $BASEDIR
+
+This is the name of your project.
+
+---
+
+##### `commitGenerated`Optional
+
+```typescript
+public readonly commitGenerated: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Whether to commit the managed files by default.
+
+---
+
+##### `gitIgnoreOptions`Optional
+
+```typescript
+public readonly gitIgnoreOptions: IgnoreFileOptions;
+```
+
+- *Type:* projen.IgnoreFileOptions
+
+Configuration options for .gitignore file.
+
+---
+
+##### `gitOptions`Optional
+
+```typescript
+public readonly gitOptions: GitOptions;
+```
+
+- *Type:* projen.GitOptions
+
+Configuration options for git.
+
+---
+
+##### `logging`Optional
+
+```typescript
+public readonly logging: LoggerOptions;
+```
+
+- *Type:* projen.LoggerOptions
+- *Default:* {}
+
+Configure logging options such as verbosity.
+
+---
+
+##### `outdir`Optional
+
+```typescript
+public readonly outdir: string;
+```
+
+- *Type:* string
+- *Default:* "."
+
+The root directory of the project.
+
+Relative to this directory, all files are synthesized.
+
+If this project has a parent, this directory is relative to the parent
+directory and it cannot be the same as the parent or any of it's other
+sub-projects.
+
+---
+
+##### `parent`Optional
+
+```typescript
+public readonly parent: Project;
+```
+
+- *Type:* projen.Project
+
+The parent project, if this project is part of a bigger project.
+
+---
+
+##### `projenCommand`Optional
+
+```typescript
+public readonly projenCommand: string;
+```
+
+- *Type:* string
+- *Default:* "npx projen"
+
+The shell command to use in order to run the projen CLI.
+
+Can be used to customize in special environments.
+
+---
+
+##### `projenrcJson`Optional
+
+```typescript
+public readonly projenrcJson: boolean;
+```
+
+- *Type:* boolean
+- *Default:* false
+
+Generate (once) .projenrc.json (in JSON). Set to `false` in order to disable .projenrc.json generation.
+
+---
+
+##### `projenrcJsonOptions`Optional
+
+```typescript
+public readonly projenrcJsonOptions: ProjenrcJsonOptions;
+```
+
+- *Type:* projen.ProjenrcJsonOptions
+- *Default:* default options
+
+Options for .projenrc.json.
+
+---
+
+##### `renovatebot`Optional
+
+```typescript
+public readonly renovatebot: boolean;
+```
+
+- *Type:* boolean
+- *Default:* false
+
+Use renovatebot to handle dependency upgrades.
+
+---
+
+##### `renovatebotOptions`Optional
+
+```typescript
+public readonly renovatebotOptions: RenovatebotOptions;
+```
+
+- *Type:* projen.RenovatebotOptions
+- *Default:* default options
+
+Options for renovatebot.
+
+---
+
+##### `autoApproveOptions`Optional
+
+```typescript
+public readonly autoApproveOptions: AutoApproveOptions;
+```
+
+- *Type:* projen.github.AutoApproveOptions
+- *Default:* auto approve is disabled
+
+Enable and configure the 'auto approve' workflow.
+
+---
+
+##### `autoMerge`Optional
+
+```typescript
+public readonly autoMerge: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Enable automatic merging on GitHub.
+
+Has no effect if `github.mergify`
+is set to false.
+
+---
+
+##### `autoMergeOptions`Optional
+
+```typescript
+public readonly autoMergeOptions: AutoMergeOptions;
+```
+
+- *Type:* projen.github.AutoMergeOptions
+- *Default:* see defaults in `AutoMergeOptions`
+
+Configure options for automatic merging on GitHub.
+
+Has no effect if
+`github.mergify` or `autoMerge` is set to false.
+
+---
+
+##### `clobber`Optional
+
+```typescript
+public readonly clobber: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true, but false for subprojects
+
+Add a `clobber` task which resets the repo to origin.
+
+---
+
+##### `devContainer`Optional
+
+```typescript
+public readonly devContainer: boolean;
+```
+
+- *Type:* boolean
+- *Default:* false
+
+Add a VSCode development environment (used for GitHub Codespaces).
+
+---
+
+##### `github`Optional
+
+```typescript
+public readonly github: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Enable GitHub integration.
+
+Enabled by default for root projects. Disabled for non-root projects.
+
+---
+
+##### `githubOptions`Optional
+
+```typescript
+public readonly githubOptions: GitHubOptions;
+```
+
+- *Type:* projen.github.GitHubOptions
+- *Default:* see GitHubOptions
+
+Options for GitHub integration.
+
+---
+
+##### `gitpod`Optional
+
+```typescript
+public readonly gitpod: boolean;
+```
+
+- *Type:* boolean
+- *Default:* false
+
+Add a Gitpod development environment.
+
+---
+
+##### ~~`mergify`~~Optional
+
+- *Deprecated:* use `githubOptions.mergify` instead
+
+```typescript
+public readonly mergify: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Whether mergify should be enabled on this repository or not.
+
+---
+
+##### ~~`mergifyOptions`~~Optional
+
+- *Deprecated:* use `githubOptions.mergifyOptions` instead
+
+```typescript
+public readonly mergifyOptions: MergifyOptions;
+```
+
+- *Type:* projen.github.MergifyOptions
+- *Default:* default options
+
+Options for mergify.
+
+---
+
+##### ~~`projectType`~~Optional
+
+- *Deprecated:* no longer supported at the base project level
+
+```typescript
+public readonly projectType: ProjectType;
+```
+
+- *Type:* projen.ProjectType
+- *Default:* ProjectType.UNKNOWN
+
+Which type of project this is (library/app).
+
+---
+
+##### `projenCredentials`Optional
+
+```typescript
+public readonly projenCredentials: GithubCredentials;
+```
+
+- *Type:* projen.github.GithubCredentials
+- *Default:* use a personal access token named PROJEN_GITHUB_TOKEN
+
+Choose a method of providing GitHub API access for projen workflows.
+
+---
+
+##### ~~`projenTokenSecret`~~Optional
+
+- *Deprecated:* use `projenCredentials`
+
+```typescript
+public readonly projenTokenSecret: string;
+```
+
+- *Type:* string
+- *Default:* "PROJEN_GITHUB_TOKEN"
+
+The name of a secret which includes a GitHub Personal Access Token to be used by projen workflows.
+
+This token needs to have the `repo`, `workflows`
+and `packages` scope.
+
+---
+
+##### `readme`Optional
+
+```typescript
+public readonly readme: SampleReadmeProps;
+```
+
+- *Type:* projen.SampleReadmeProps
+- *Default:* { filename: 'README.md', contents: '# replace this' }
+
+The README setup.
+
+---
+
+*Example*
+
+```typescript
+"{ filename: 'readme.md', contents: '# title' }"
+```
+
+
+##### `stale`Optional
+
+```typescript
+public readonly stale: boolean;
+```
+
+- *Type:* boolean
+- *Default:* false
+
+Auto-close of stale issues and pull request.
+
+See `staleOptions` for options.
+
+---
+
+##### `staleOptions`Optional
+
+```typescript
+public readonly staleOptions: StaleOptions;
+```
+
+- *Type:* projen.github.StaleOptions
+- *Default:* see defaults in `StaleOptions`
+
+Auto-close stale issues and pull requests.
+
+To disable set `stale` to `false`.
+
+---
+
+##### `vscode`Optional
+
+```typescript
+public readonly vscode: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Enable VSCode integration.
+
+Enabled by default for root projects. Disabled for non-root projects.
+
+---
+
+##### `author`Optional
+
+```typescript
+public readonly author: string;
+```
+
+- *Type:* string
+- *Default:* "TODO: Your Name"
+
+The name of the skill's author.
+
+---
+
+*Example*
+
+```typescript
+"Mike Gray"
+```
+
+
+##### `authorAddress`Optional
+
+```typescript
+public readonly authorAddress: string;
+```
+
+- *Type:* string
+- *Default:* "TODO: Your Email"
+
+The email address of the skill's author.
+
+---
+
+*Example*
+
+```typescript
+"mike@graywind.org"
+```
+
+
+##### `authorHandle`Optional
+
+```typescript
+public readonly authorHandle: string;
+```
+
+- *Type:* string
+- *Default:* ""
+
+The GitHub handle of the skill's author.
+
+---
+
+*Example*
+
+```typescript
+"mikejgray"
+```
+
+
+##### `condenseLocaleFolders`Optional
+
+```typescript
+public readonly condenseLocaleFolders: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Restructure locale folders to be more OVOS-like?
+
+---
+
+##### `githubWorkflows`Optional
+
+```typescript
+public readonly githubWorkflows: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Add Github Actions workflows?
+
+---
+
+##### `license`Optional
+
+```typescript
+public readonly license: string;
+```
+
+- *Type:* string
+- *Default:* Apache-2.0
+
+The license of the skill.
+
+---
+
+*Example*
+
+```typescript
+MIT
+```
+
+
+##### `packageDir`Optional
+
+```typescript
+public readonly packageDir: string;
+```
+
+- *Type:* string
+- *Default:* "" (root)
+
+The name of the directory containing the skill's code.
+
+---
+
+*Example*
+
+```typescript
+"hello_world_skill"
+```
+
+
+##### `pypiName`Optional
+
+```typescript
+public readonly pypiName: string;
+```
+
+- *Type:* string
+
+The name of the skill's PyPi package.
+
+---
+
+*Example*
+
+```typescript
+ovos-hello-world-skill
+```
+
+
+##### `repositoryUrl`Optional
+
+```typescript
+public readonly repositoryUrl: string;
+```
+
+- *Type:* string
+- *Default:* "TODO: PLACEHOLDER"
+
+The URL of the skill's GitHub repository.
+
+---
+
+*Example*
+
+```typescript
+"https://github.com/OpenVoiceOS/ovos-hello-world-skill"
+```
+
+
+##### `retrofit`Optional
+
+```typescript
+public readonly retrofit: boolean;
+```
+
+- *Type:* boolean
+- *Default:* false
+
+Retrofit an existing Mycroft skill to OVOS?
+
+---
+
+##### `sampleCode`Optional
+
+```typescript
+public readonly sampleCode: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Include sample code?
+
+---
+
+##### `skillClass`Optional
+
+```typescript
+public readonly skillClass: string;
+```
+
+- *Type:* string
+
+The name of the skill class.
+
+---
+
+*Example*
+
+```typescript
+HelloWorldSkill
+```
+
+
+##### `skillDescription`Optional
+
+```typescript
+public readonly skillDescription: string;
+```
+
+- *Type:* string
+- *Default:* ""
+
+The description of the skill.
+
+Used in setup.py.
+
+---
+
+*Example*
+
+```typescript
+"A simple skill that says hello world"
+```
+
+
+##### `skillKeywords`Optional
+
+```typescript
+public readonly skillKeywords: string;
+```
+
+- *Type:* string
+- *Default:* "ovos skill plugin"
+
+Keywords for your skill package.
+
+---
+
+##### `skillLicenseTest`Optional
+
+```typescript
+public readonly skillLicenseTest: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Include a test to check that the skill's license is FOSS?
+
+---
+
+## Classes
+
+### OVOSPHALProject
+
+#### Initializers
+
+```typescript
+import { OVOSPHALProject } from '@mikejgray/ovos-skill-projen'
+
+new OVOSPHALProject(options: OVOSPHALProjectOptions)
+```
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| options
| OVOSPHALProjectOptions
| *No description.* |
+
+---
+
+##### `options`Required
+
+- *Type:* OVOSPHALProjectOptions
+
+---
+
+#### Methods
+
+| **Name** | **Description** |
+| --- | --- |
+| addExcludeFromCleanup
| Exclude the matching files from pre-synth cleanup. |
+| addGitIgnore
| Adds a .gitignore pattern. |
+| addPackageIgnore
| Exclude these files from the bundled package. |
+| addTask
| Adds a new task to this project. |
+| addTip
| Prints a "tip" message during synthesis. |
+| annotateGenerated
| Marks the provided file(s) as being generated. |
+| postSynthesize
| Called after all components are synthesized. |
+| preSynthesize
| Called before all components are synthesized. |
+| removeTask
| Removes a task from a project. |
+| runTaskCommand
| Returns the shell command to execute in order to run a task. |
+| synth
| Synthesize all project files into `outdir`. |
+| tryFindFile
| Finds a file at the specified relative path within this project and all its subprojects. |
+| tryFindJsonFile
| Finds a json file by name. |
+| tryFindObjectFile
| Finds an object file (like JsonFile, YamlFile, etc.) by name. |
+| tryRemoveFile
| Finds a file at the specified relative path within this project and removes it. |
+| addPythonGitIgnore
| *No description.* |
+| createDevBranch
| Create a dev branch if it doesn't already exist, and set it as the default branch. |
+| createGenericSkillCode
| Create a generic skill with sample code. |
+
+---
+
+##### `addExcludeFromCleanup`
+
+```typescript
+public addExcludeFromCleanup(globs: string): void
+```
+
+Exclude the matching files from pre-synth cleanup.
+
+Can be used when, for example, some
+source files include the projen marker and we don't want them to be erased during synth.
+
+###### `globs`Required
+
+- *Type:* string
+
+The glob patterns to match.
+
+---
+
+##### `addGitIgnore`
+
+```typescript
+public addGitIgnore(pattern: string): void
+```
+
+Adds a .gitignore pattern.
+
+###### `pattern`Required
+
+- *Type:* string
+
+The glob pattern to ignore.
+
+---
+
+##### `addPackageIgnore`
+
+```typescript
+public addPackageIgnore(_pattern: string): void
+```
+
+Exclude these files from the bundled package.
+
+Implemented by project types based on the
+packaging mechanism. For example, `NodeProject` delegates this to `.npmignore`.
+
+###### `_pattern`Required
+
+- *Type:* string
+
+The glob pattern to exclude.
+
+---
+
+##### `addTask`
+
+```typescript
+public addTask(name: string, props?: TaskOptions): Task
+```
+
+Adds a new task to this project.
+
+This will fail if the project already has
+a task with this name.
+
+###### `name`Required
+
+- *Type:* string
+
+The task name to add.
+
+---
+
+###### `props`Optional
+
+- *Type:* projen.TaskOptions
+
+Task properties.
+
+---
+
+##### ~~`addTip`~~
+
+```typescript
+public addTip(message: string): void
+```
+
+Prints a "tip" message during synthesis.
+
+###### `message`Required
+
+- *Type:* string
+
+The message.
+
+---
+
+##### `annotateGenerated`
+
+```typescript
+public annotateGenerated(glob: string): void
+```
+
+Marks the provided file(s) as being generated.
+
+This is achieved using the
+github-linguist attributes. Generated files do not count against the
+repository statistics and language breakdown.
+
+> [https://github.com/github/linguist/blob/master/docs/overrides.md](https://github.com/github/linguist/blob/master/docs/overrides.md)
+
+###### `glob`Required
+
+- *Type:* string
+
+the glob pattern to match (could be a file path).
+
+---
+
+##### `postSynthesize`
+
+```typescript
+public postSynthesize(): void
+```
+
+Called after all components are synthesized.
+
+Order is *not* guaranteed.
+
+##### `preSynthesize`
+
+```typescript
+public preSynthesize(): void
+```
+
+Called before all components are synthesized.
+
+##### `removeTask`
+
+```typescript
+public removeTask(name: string): Task
+```
+
+Removes a task from a project.
+
+###### `name`Required
+
+- *Type:* string
+
+The name of the task to remove.
+
+---
+
+##### `runTaskCommand`
+
+```typescript
+public runTaskCommand(task: Task): string
+```
+
+Returns the shell command to execute in order to run a task.
+
+By default, this is `npx projen@ `
+
+###### `task`Required
+
+- *Type:* projen.Task
+
+The task for which the command is required.
+
+---
+
+##### `synth`
+
+```typescript
+public synth(): void
+```
+
+Synthesize all project files into `outdir`.
+
+1. Call "this.preSynthesize()"
+2. Delete all generated files
+3. Synthesize all sub-projects
+4. Synthesize all components of this project
+5. Call "postSynthesize()" for all components of this project
+6. Call "this.postSynthesize()"
+
+##### `tryFindFile`
+
+```typescript
+public tryFindFile(filePath: string): FileBase
+```
+
+Finds a file at the specified relative path within this project and all its subprojects.
+
+###### `filePath`Required
+
+- *Type:* string
+
+The file path.
+
+If this path is relative, it will be resolved
+from the root of _this_ project.
+
+---
+
+##### ~~`tryFindJsonFile`~~
+
+```typescript
+public tryFindJsonFile(filePath: string): JsonFile
+```
+
+Finds a json file by name.
+
+###### `filePath`Required
+
+- *Type:* string
+
+The file path.
+
+---
+
+##### `tryFindObjectFile`
+
+```typescript
+public tryFindObjectFile(filePath: string): ObjectFile
+```
+
+Finds an object file (like JsonFile, YamlFile, etc.) by name.
+
+###### `filePath`Required
+
+- *Type:* string
+
+The file path.
+
+---
+
+##### `tryRemoveFile`
+
+```typescript
+public tryRemoveFile(filePath: string): FileBase
+```
+
+Finds a file at the specified relative path within this project and removes it.
+
+###### `filePath`Required
+
+- *Type:* string
+
+The file path.
+
+If this path is relative, it will be
+resolved from the root of _this_ project.
+
+---
+
+##### `addPythonGitIgnore`
+
+```typescript
+public addPythonGitIgnore(): void
+```
+
+##### `createDevBranch`
+
+```typescript
+public createDevBranch(): void
+```
+
+Create a dev branch if it doesn't already exist, and set it as the default branch.
+
+##### `createGenericSkillCode`
+
+```typescript
+public createGenericSkillCode(dir: string): void
+```
+
+Create a generic skill with sample code.
+
+*Example*
+
+```typescript
+"neon_phal_plugin_audio_receiver"
+```
+
+
+###### `dir`Required
+
+- *Type:* string
+
+The name of the directory to create sample code in.
+
+---
+
+
+#### Properties
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| buildTask
| projen.Task
| *No description.* |
+| commitGenerated
| boolean
| Whether to commit the managed files by default. |
+| compileTask
| projen.Task
| *No description.* |
+| components
| projen.Component[]
| Returns all the components within this project. |
+| deps
| projen.Dependencies
| Project dependencies. |
+| ejected
| boolean
| Whether or not the project is being ejected. |
+| files
| projen.FileBase[]
| All files in this project. |
+| gitattributes
| projen.GitAttributesFile
| The .gitattributes file for this repository. |
+| gitignore
| projen.IgnoreFile
| .gitignore. |
+| logger
| projen.Logger
| Logging utilities. |
+| name
| string
| Project name. |
+| outdir
| string
| Absolute output directory of this project. |
+| packageTask
| projen.Task
| *No description.* |
+| postCompileTask
| projen.Task
| *No description.* |
+| preCompileTask
| projen.Task
| *No description.* |
+| projectBuild
| projen.ProjectBuild
| Manages the build process of the project. |
+| projenCommand
| string
| The command to use in order to run the projen CLI. |
+| root
| projen.Project
| The root project. |
+| subprojects
| projen.Project[]
| Returns all the subprojects within this project. |
+| tasks
| projen.Tasks
| Project tasks. |
+| testTask
| projen.Task
| *No description.* |
+| defaultTask
| projen.Task
| This is the "default" task, the one that executes "projen". |
+| initProject
| projen.InitProject
| The options used when this project is bootstrapped via `projen new`. |
+| parent
| projen.Project
| A parent project. |
+| projectType
| projen.ProjectType
| *No description.* |
+| autoApprove
| projen.github.AutoApprove
| Auto approve set up for this project. |
+| devContainer
| projen.vscode.DevContainer
| Access for .devcontainer.json (used for GitHub Codespaces). |
+| github
| projen.github.GitHub
| Access all github components. |
+| gitpod
| projen.Gitpod
| Access for Gitpod. |
+| vscode
| projen.vscode.VsCode
| Access all VSCode components. |
+
+---
+
+##### `buildTask`Required
+
+```typescript
+public readonly buildTask: Task;
+```
+
+- *Type:* projen.Task
+
+---
+
+##### `commitGenerated`Required
+
+```typescript
+public readonly commitGenerated: boolean;
+```
+
+- *Type:* boolean
+
+Whether to commit the managed files by default.
+
+---
+
+##### `compileTask`Required
+
+```typescript
+public readonly compileTask: Task;
+```
+
+- *Type:* projen.Task
+
+---
+
+##### `components`Required
+
+```typescript
+public readonly components: Component[];
+```
+
+- *Type:* projen.Component[]
+
+Returns all the components within this project.
+
+---
+
+##### `deps`Required
+
+```typescript
+public readonly deps: Dependencies;
+```
+
+- *Type:* projen.Dependencies
+
+Project dependencies.
+
+---
+
+##### `ejected`Required
+
+```typescript
+public readonly ejected: boolean;
+```
+
+- *Type:* boolean
+
+Whether or not the project is being ejected.
+
+---
+
+##### `files`Required
+
+```typescript
+public readonly files: FileBase[];
+```
+
+- *Type:* projen.FileBase[]
+
+All files in this project.
+
+---
+
+##### `gitattributes`Required
+
+```typescript
+public readonly gitattributes: GitAttributesFile;
+```
+
+- *Type:* projen.GitAttributesFile
+
+The .gitattributes file for this repository.
+
+---
+
+##### `gitignore`Required
+
+```typescript
+public readonly gitignore: IgnoreFile;
+```
+
+- *Type:* projen.IgnoreFile
+
+.gitignore.
+
+---
+
+##### `logger`Required
+
+```typescript
+public readonly logger: Logger;
+```
+
+- *Type:* projen.Logger
+
+Logging utilities.
+
+---
+
+##### `name`Required
+
+```typescript
+public readonly name: string;
+```
+
+- *Type:* string
+
+Project name.
+
+---
+
+##### `outdir`Required
+
+```typescript
+public readonly outdir: string;
+```
+
+- *Type:* string
+
+Absolute output directory of this project.
+
+---
+
+##### `packageTask`Required
+
+```typescript
+public readonly packageTask: Task;
+```
+
+- *Type:* projen.Task
+
+---
+
+##### `postCompileTask`Required
+
+```typescript
+public readonly postCompileTask: Task;
+```
+
+- *Type:* projen.Task
+
+---
+
+##### `preCompileTask`Required
+
+```typescript
+public readonly preCompileTask: Task;
+```
+
+- *Type:* projen.Task
+
+---
+
+##### `projectBuild`Required
+
+```typescript
+public readonly projectBuild: ProjectBuild;
+```
+
+- *Type:* projen.ProjectBuild
+
+Manages the build process of the project.
+
+---
+
+##### `projenCommand`Required
+
+```typescript
+public readonly projenCommand: string;
+```
+
+- *Type:* string
+
+The command to use in order to run the projen CLI.
+
+---
+
+##### `root`Required
+
+```typescript
+public readonly root: Project;
+```
+
+- *Type:* projen.Project
+
+The root project.
+
+---
+
+##### `subprojects`Required
+
+```typescript
+public readonly subprojects: Project[];
+```
+
+- *Type:* projen.Project[]
+
+Returns all the subprojects within this project.
+
+---
+
+##### `tasks`Required
+
+```typescript
+public readonly tasks: Tasks;
+```
+
+- *Type:* projen.Tasks
+
+Project tasks.
+
+---
+
+##### `testTask`Required
+
+```typescript
+public readonly testTask: Task;
+```
+
+- *Type:* projen.Task
+
+---
+
+##### `defaultTask`Optional
+
+```typescript
+public readonly defaultTask: Task;
+```
+
+- *Type:* projen.Task
+
+This is the "default" task, the one that executes "projen".
+
+Undefined if
+the project is being ejected.
+
+---
+
+##### `initProject`Optional
+
+```typescript
+public readonly initProject: InitProject;
+```
+
+- *Type:* projen.InitProject
+
+The options used when this project is bootstrapped via `projen new`.
+
+It
+includes the original set of options passed to the CLI and also the JSII
+FQN of the project type.
+
+---
+
+##### `parent`Optional
+
+```typescript
+public readonly parent: Project;
+```
+
+- *Type:* projen.Project
+
+A parent project.
+
+If undefined, this is the root project.
+
+---
+
+##### `projectType`Required
+
+```typescript
+public readonly projectType: ProjectType;
+```
+
+- *Type:* projen.ProjectType
+
+---
+
+##### `autoApprove`Optional
+
+```typescript
+public readonly autoApprove: AutoApprove;
+```
+
+- *Type:* projen.github.AutoApprove
+
+Auto approve set up for this project.
+
+---
+
+##### `devContainer`Optional
+
+```typescript
+public readonly devContainer: DevContainer;
+```
+
+- *Type:* projen.vscode.DevContainer
+
+Access for .devcontainer.json (used for GitHub Codespaces).
+
+This will be `undefined` if devContainer boolean is false
+
+---
+
+##### `github`Optional
+
+```typescript
+public readonly github: GitHub;
+```
+
+- *Type:* projen.github.GitHub
+
+Access all github components.
+
+This will be `undefined` for subprojects.
+
+---
+
+##### `gitpod`Optional
+
+```typescript
+public readonly gitpod: Gitpod;
+```
+
+- *Type:* projen.Gitpod
+
+Access for Gitpod.
+
+This will be `undefined` if gitpod boolean is false
+
+---
+
+##### `vscode`Optional
+
+```typescript
+public readonly vscode: VsCode;
+```
+
+- *Type:* projen.vscode.VsCode
+
+Access all VSCode components.
+
+This will be `undefined` for subprojects.
+
+---
+
+#### Constants
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| DEFAULT_TASK
| string
| The name of the default task (the task executed when `projen` is run without arguments). |
+
+---
+
+##### `DEFAULT_TASK`Required
+
+```typescript
+public readonly DEFAULT_TASK: string;
+```
+
+- *Type:* string
+
+The name of the default task (the task executed when `projen` is run without arguments).
+
+Normally
+this task should synthesize the project files.
+
+---
### OVOSSkillProject
diff --git a/README.md b/README.md
index 176f18f..49b2704 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,7 @@ Add that to your `~/.bashrc` or `~/.zshrc` file to make it permanent. Be sure to
In a new directory, run:
-`projen new ovosskill --from "@mikejgray/ovos-skill-projen@latest"`
+`npx projen new ovosskill --from "@mikejgray/ovos-skill-projen@latest"`
**NOTE**: This repo is not yet available on NPM. Please add the following to your `~/.npmrc` file (create one if it doesn't exist), with [a GitHub token that has packages:read permissions](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-npm-registry):
@@ -52,6 +52,26 @@ Example:
After editing `.projenrc.json`, run `pj` to regenerate the project files. This can automatically keep your project up to date with the latest changes, including managing your `setup.py` file.
+## Create a new PHAL plugin template
+
+In a new directory, run:
+
+`npx projen new ovosphal --from "@mikejgray/ovos-skill-projen@latest"`
+
+The instructions are the same as for creating a new skill template, except that you have an additional option to set the PHAL plugin as admin or not. The default is `false`, indicating that the PHAL plugin will not run as root.
+
+**NOTE:** If you do set the PHAL plugin to `admin` and thus run as root, you will also need to update your OVOS config to explicitly allow your root plugins. This is a security risk and should only be done if you understand the implications. For more information about Admin PHAL, [see the OVOS technical manual](https://openvoiceos.github.io/ovos-technical-manual/PHAL/#admin-phal).
+
+Example OVOS config:
+
+```json
+{
+ "PHAL": {
+ "admin": "ovos-phal-plugin-helloworld": {"enabled": true}
+ }
+}
+```
+
### setup.py ownership
Note that projen takes ownership of the `setup.py` file, and the expectation is that manual edits are not allowed. If you need to make changes to the `setup.py` file, you should do so by editing `.projenrc.json` and running `pj` to regenerate the file.
diff --git a/src/files/README.phal.ts b/src/files/README.phal.ts
new file mode 100644
index 0000000..de40520
--- /dev/null
+++ b/src/files/README.phal.ts
@@ -0,0 +1,24 @@
+interface readmePhalInterface {
+ skillClass: string;
+ authorName: string;
+ authorHandle: string;
+};
+
+export const readmePhalMd = ({
+ skillClass,
+ authorName,
+ authorHandle,
+}: readmePhalInterface): string => {
+ return `# ${skillClass}
+
+Template for an OVOS PHAL plugin.
+
+\`\`\`python
+self.bus.on("mycroft.ready", self.on_mycroft_ready)
+\`\`\`
+
+## Credits
+
+${authorName} (@${authorHandle})
+`;
+};
diff --git a/src/files/__init__.phal.py b/src/files/__init__.phal.py
new file mode 100644
index 0000000..9f434d9
--- /dev/null
+++ b/src/files/__init__.phal.py
@@ -0,0 +1,28 @@
+from ovos_bus_client import Message
+from ovos_plugin_manager.phal import PHALPlugin
+
+
+class HelloWorldPlugin(PHALPlugin):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.bus.on("mycroft.ready", self.on_mycroft_ready)
+
+ @property
+ def my_setting(self):
+ """Dynamically get the my_setting from the config file(s).
+ Example:
+ {
+ "PHAL": {
+ "ovos-phal-plugin-helloworld": {
+ "my_setting": "my_value"
+ }
+ }
+ }
+ If it doesn't exist, return the default value.
+ """
+ return self.config.get("my_setting", "default_value")
+
+ def on_mycroft_ready(self, message: Message):
+ """Take action when OVOS is ready."""
+ self.log.info("OVOS reported ready, now I can do something!")
+ # Implement something here
diff --git a/src/files/setup.py.phal.ts b/src/files/setup.py.phal.ts
new file mode 100644
index 0000000..76d6e2e
--- /dev/null
+++ b/src/files/setup.py.phal.ts
@@ -0,0 +1,135 @@
+interface setupPyInterface {
+ /**
+ * The URL of the plugin's GitHub repository.
+ */
+ repositoryUrl: string;
+ /**
+ * The name of the directory containing the plugin's code.
+ * @default "" (root)
+ */
+ packageDir: string;
+ /**
+ * The name of the plugin's author.
+ */
+ author: string;
+ /**
+ * The email address of the plugin's author.
+ */
+ authorAddress: string;
+ /**
+ * The name of the plugin class.
+ */
+ pluginClass: string;
+ /**
+ * The name of the plugin's PyPi package.
+ */
+ pypiName: string;
+ /**
+ * The description of the plugin.
+ */
+ description: string;
+ /**
+ * The license of the plugin.
+ */
+ license: string;
+ /**
+ * Whether the plugin is an admin PHAL plugin, meaning it runs as root.
+ * @default false
+ */
+ admin?: boolean;
+}
+
+export const setupPhalPy = ({
+ repositoryUrl,
+ packageDir,
+ author,
+ authorAddress,
+ pypiName,
+ pluginClass,
+ description,
+ license,
+ admin,
+}: setupPyInterface): string => {
+ return `#!/usr/bin/env python3
+from setuptools import setup
+from os import walk, path
+
+BASEDIR = path.abspath(path.dirname(__file__))
+URL = "${repositoryUrl}"
+plugin_CLAZZ = "${pluginClass}" # needs to match __init__.py class name
+PYPI_NAME = "${pypiName}" # pip install PYPI_NAME
+
+# below derived from github url to ensure standard plugin_id
+plugin_AUTHOR, plugin_NAME = URL.split(".com/")[-1].split("/")
+plugin_PKG = plugin_NAME.lower().replace("-", "_")
+PLUGIN_ENTRY_POINT = f"{plugin_NAME.lower()}.{plugin_AUTHOR.lower()}={plugin_PKG}:{plugin_CLAZZ}"
+# plugin_id=package_name:pluginClass
+BASE_PATH = BASE_PATH = path.abspath(path.join(path.dirname(__file__), "${packageDir}"))
+
+
+def get_version():
+ """Find the version of the package"""
+ version = None
+ version_file = path.join(BASE_PATH, "version.py")
+ major, minor, build, alpha = (None, None, None, None)
+ with open(version_file) as f:
+ for line in f:
+ if "VERSION_MAJOR" in line:
+ major = line.split("=")[1].strip()
+ elif "VERSION_MINOR" in line:
+ minor = line.split("=")[1].strip()
+ elif "VERSION_BUILD" in line:
+ build = line.split("=")[1].strip()
+ elif "VERSION_ALPHA" in line:
+ alpha = line.split("=")[1].strip()
+
+ if (major and minor and build and alpha) or "# END_VERSION_BLOCK" in line:
+ break
+ version = f"{major}.{minor}.{build}"
+ if alpha and int(alpha) > 0:
+ version += f"a{alpha}"
+ return version
+
+
+def get_requirements(requirements_filename: str):
+ requirements_file = path.join(path.dirname(__file__), requirements_filename)
+ with open(requirements_file, "r", encoding="utf-8") as r:
+ requirements = r.readlines()
+ requirements = [r.strip() for r in requirements if r.strip() and not r.strip().startswith("#")]
+ return requirements
+
+
+def find_resource_files():
+ resource_base_dirs = ("locale", "intents", "dialog", "vocab", "regex", "ui")
+ package_data = ["*.json"]
+ for res in resource_base_dirs:
+ if path.isdir(path.join(BASE_PATH, res)):
+ for directory, _, files in walk(path.join(BASE_PATH, res)):
+ if files:
+ package_data.append(path.join(directory.replace(BASE_PATH, "").lstrip("/"), "*"))
+ return package_data
+
+
+with open("README.md", "r") as f:
+ long_description = f.read()
+
+setup(
+ name=PYPI_NAME,
+ version=get_version(),
+ description="${description}",
+ long_description=long_description,
+ long_description_content_type="text/markdown",
+ url=URL,
+ author="${author}",
+ author_email="${authorAddress}",
+ license="${license}",
+ package_dir={plugin_PKG: "${packageDir ?? '.'}"},
+ package_data={plugin_PKG: find_resource_files()},
+ packages=[plugin_PKG],
+ include_package_data=True,
+ install_requires=get_requirements("requirements.txt"),
+ keywords="ovos plugin voice assistant",
+ entry_points={${admin ? 'ovos.plugin.phal.admin' : 'ovos.plugin.phal'}: PLUGIN_ENTRY_POINT},
+)
+`;
+};
\ No newline at end of file
diff --git a/src/files/setup.py.ts b/src/files/setup.py.ts
index 8866016..0994f41 100644
--- a/src/files/setup.py.ts
+++ b/src/files/setup.py.ts
@@ -1,4 +1,4 @@
-interface setupPyInterface {
+export interface setupPyInterface {
/**
* The URL of the skill's GitHub repository.
*/
diff --git a/src/index.ts b/src/index.ts
index 46b4992..8f32145 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -5,7 +5,9 @@ import { ProjenrcJson, SampleDir, SampleFile, TextFile } from 'projen';
import { GitHubProject, GitHubProjectOptions } from 'projen/lib/github';
import { parse } from 'yaml';
import { readmeMd } from './files/README';
+import { readmePhalMd } from './files/README.phal';
import { setupPy } from './files/setup.py';
+import { setupPhalPy } from './files/setup.py.phal';
import { LicenseTestsWorkflow, ProposeReleaseWorkflow, PublishAlphaWorkflow, PublishReleaseWorkflow, SkillTestsWorkflow, UpdateSkillJsonWorkflow } from './GithubWorkflows';
export interface OVOSSkillProjectOptions extends GitHubProjectOptions {
@@ -457,3 +459,217 @@ ${line}`;
}
}
+
+export interface OVOSPHALProjectOptions extends OVOSSkillProjectOptions {
+ /**
+ * Is this an admin PHAL plugin?
+ * @default false
+ */
+ readonly admin?: boolean;
+}
+export class OVOSPHALProject extends GitHubProject {
+ constructor(options: OVOSPHALProjectOptions) {
+ let superProps = { ...options };
+ superProps.readme = {
+ contents: readmePhalMd({
+ skillClass: options.skillClass ?? 'OVOSSkill',
+ authorName: options.author ?? 'authorName',
+ authorHandle: options.authorHandle ?? 'githubUsername',
+ }),
+ };
+ super(superProps);
+
+ const author = options.author ?? 'TODO: Add \'author\' to .projenrc.json and run pj';
+ const repositoryUrl = options.repositoryUrl ?? 'TODO: Add \'repositoryUrl\' to .projenrc.json and run pj';
+ const authorAddress = options.authorAddress ?? 'TODO: Add \'authorAddress\' to .projenrc.json and run pj';
+ const license = options.license ?? '# TODO: Add \'license\' to .projenrc.json and run pj';
+ const skillClass = options.skillClass ?? 'TODO: Add \'skillClass\' to .projenrc.json and run pj';
+ const pypiName = options.pypiName ?? process.cwd().split('/').pop()!;
+ const packageDir = options.packageDir ?? 'src';
+ const skillDescription = options.skillDescription ?? '';
+ const admin = options.admin ?? false;
+ new TextFile(this, 'setup.py', {
+ lines: setupPhalPy({
+ repositoryUrl,
+ packageDir,
+ pypiName,
+ author,
+ authorAddress,
+ license,
+ description: skillDescription,
+ pluginClass: skillClass,
+ admin,
+ }).split('\n'),
+ });
+ new TextFile(this, 'version.py', {
+ lines: 'VERSION_MAJOR = 0\nVERSION_MINOR = 0\nVERSION_BUILD = 1\nVERSION_ALPHA = 0'.split('\n'),
+ });
+ // projenrc.json
+ new ProjenrcJson(this, {});
+ // gitignore
+ this.gitignore.addPatterns('.DS_Store', 'node_modules');
+ this.addPythonGitIgnore();
+ this.createGenericSkillCode(packageDir);
+ let requirements = 'ovos-utils\novos-bus-client\novos-workshop\novos-plugin-manager\n# Your requirements here\n';
+ new SampleFile(this, 'requirements.txt', {
+ contents: requirements,
+ });
+ this.createDevBranch();
+ }
+ // Methods
+ /**
+ * Create a generic skill with sample code.
+ * @param dir The name of the directory to create sample code in
+ * @default "src"
+ * @example "neon_phal_plugin_audio_receiver"
+ */
+ createGenericSkillCode(dir: string) {
+ new SampleDir(this, dir, {
+ files: {
+ '__init__.py': readFileSync(join(__dirname, 'files', '__init__.phal.py')).toString(),
+ 'version.py': 'VERSION_MAJOR = 0\nVERSION_MINOR = 0\nVERSION_BUILD = 1\nVERSION_ALPHA = 0',
+ },
+ });
+ }
+ /**
+ * Create a dev branch if it doesn't already exist, and set it as the default branch.
+ */
+ createDevBranch() {
+ exec('git rev-parse --verify dev', (err) => {
+ if (err) {
+ exec('git checkout -b dev');
+ exec('git branch -M dev');
+ }
+ });
+ }
+ addPythonGitIgnore() {
+ this.gitignore.exclude(
+ '# Byte-compiled / optimized / DLL files',
+ '__pycache__/',
+ '*.py[cod]',
+ '*$py.class',
+ '',
+ '# C extensions',
+ '*.so',
+ '',
+ '# Distribution / packaging',
+ '.Python',
+ 'build/',
+ 'develop-eggs/',
+ 'dist/',
+ 'downloads/',
+ 'eggs/',
+ '.eggs/',
+ 'lib/',
+ 'lib64/',
+ 'parts/',
+ 'sdist/',
+ 'var/',
+ 'wheels/',
+ 'share/python-wheels/',
+ '*.egg-info/',
+ '.installed.cfg',
+ '*.egg',
+ 'MANIFEST',
+ '',
+ '# PyInstaller',
+ '# Usually these files are written by a python script from a template',
+ '# before PyInstaller builds the exe, so as to inject date/other infos into it.',
+ '*.manifest',
+ '*.spec',
+ '',
+ '# Installer logs',
+ 'pip-log.txt',
+ 'pip-delete-this-directory.txt',
+ '',
+ '# Unit test / coverage reports',
+ 'htmlcov/',
+ '.tox/',
+ '.nox/',
+ '.coverage',
+ '.coverage.*',
+ '.cache',
+ 'nosetests.xml',
+ 'coverage.xml',
+ '*.cover',
+ '*.py,cover',
+ '.hypothesis/',
+ '.pytest_cache/',
+ 'cover/',
+ '',
+ '# Translations',
+ '*.mo',
+ '*.pot',
+ '',
+ '# Django stuff:',
+ '*.log',
+ 'local_settings.py',
+ 'db.sqlite3',
+ 'db.sqlite3-journal',
+ '',
+ '# Flask stuff:',
+ 'instance/',
+ '.webassets-cache',
+ '',
+ '# Scrapy stuff:',
+ '.scrapy',
+ '',
+ '# Sphinx documentation',
+ 'docs/_build/',
+ '',
+ '# PyBuilder',
+ '.pybuilder/',
+ 'target/',
+ '',
+ '# Jupyter Notebook',
+ '.ipynb_checkpoints',
+ '',
+ '# IPython',
+ 'profile_default/',
+ 'ipython_config.py',
+ '',
+ '# PEP 582; used by e.g. github.com/David-OConnor/pyflow',
+ '__pypackages__/',
+ '',
+ '# Celery stuff',
+ 'celerybeat-schedule',
+ 'celerybeat.pid',
+ '',
+ '# SageMath parsed files',
+ '*.sage.py',
+ '',
+ '# Environments',
+ '.env',
+ '.venv',
+ 'env/',
+ 'venv/',
+ 'ENV/',
+ 'env.bak/',
+ 'venv.bak/',
+ '',
+ '# Spyder project settings',
+ '.spyderproject',
+ '.spyproject',
+ '',
+ '# Rope project settings',
+ '.ropeproject',
+ '',
+ '# mkdocs documentation',
+ '/site',
+ '',
+ '# mypy',
+ '.mypy_cache/',
+ '.dmypy.json',
+ 'dmypy.json',
+ '',
+ '# Pyre type checker',
+ '.pyre/',
+ '',
+ '# pytype static type analyzer',
+ '.pytype/',
+ '',
+ '# Cython debug symbols',
+ 'cython_debug/',
+ );
+ }
+}
diff --git a/test/OVOSPHALProject.test.ts b/test/OVOSPHALProject.test.ts
new file mode 100644
index 0000000..7d5bd36
--- /dev/null
+++ b/test/OVOSPHALProject.test.ts
@@ -0,0 +1,15 @@
+import { Testing } from 'projen';
+import { OVOSPHALProject } from '../src';
+
+test('snapshot', () => {
+ const project = new OVOSPHALProject({
+ name: 'test',
+ skillClass: 'TestPlugin',
+ pypiName: 'test-plugin',
+ });
+
+ const synth = Testing.synth(project);
+ expect(synth).toMatchSnapshot();
+ expect(synth['requirements.txt']).toBeDefined();
+ expect(synth['requirements.txt']).toContain('ovos-utils\novos-bus-client\novos-workshop');
+});
diff --git a/test/__snapshots__/OVOSPHALProject.test.ts.snap b/test/__snapshots__/OVOSPHALProject.test.ts.snap
new file mode 100644
index 0000000..faf8cdc
--- /dev/null
+++ b/test/__snapshots__/OVOSPHALProject.test.ts.snap
@@ -0,0 +1,388 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`snapshot 1`] = `
+Object {
+ ".gitattributes": "# ~~ Generated by projen. To modify, edit .projenrc.json and run \\"npx projen\\".
+
+/.gitattributes linguist-generated
+/.github/workflows/pull-request-lint.yml linguist-generated
+/.gitignore linguist-generated
+/.projen/** linguist-generated
+/.projen/deps.json linguist-generated
+/.projen/files.json linguist-generated
+/.projen/tasks.json linguist-generated
+/setup.py linguist-generated
+/version.py linguist-generated",
+ ".github/workflows/pull-request-lint.yml": "# ~~ Generated by projen. To modify, edit .projenrc.json and run \\"npx projen\\".
+
+name: pull-request-lint
+on:
+ pull_request_target:
+ types:
+ - labeled
+ - opened
+ - synchronize
+ - reopened
+ - ready_for_review
+ - edited
+jobs:
+ validate:
+ name: Validate PR title
+ runs-on: ubuntu-latest
+ permissions:
+ pull-requests: write
+ steps:
+ - uses: amannn/action-semantic-pull-request@v5.0.2
+ env:
+ GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
+ with:
+ types: |-
+ feat
+ fix
+ chore
+ requireScope: false
+",
+ ".gitignore": "# ~~ Generated by projen. To modify, edit .projenrc.json and run \\"npx projen\\".
+node_modules/
+!/.gitattributes
+!/.projen/tasks.json
+!/.projen/deps.json
+!/.projen/files.json
+!/.github/workflows/pull-request-lint.yml
+!/setup.py
+!/version.py
+.DS_Store
+node_modules
+__pycache__/
+*.py[cod]
+*$py.class
+*.so
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+*.manifest
+*.spec
+pip-log.txt
+pip-delete-this-directory.txt
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+*.mo
+*.pot
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+instance/
+.webassets-cache
+.scrapy
+docs/_build/
+.pybuilder/
+target/
+.ipynb_checkpoints
+profile_default/
+ipython_config.py
+__pypackages__/
+celerybeat-schedule
+celerybeat.pid
+*.sage.py
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+.spyderproject
+.spyproject
+.ropeproject
+/site
+.mypy_cache/
+.dmypy.json
+dmypy.json
+.pyre/
+.pytype/
+cython_debug/
+",
+ ".projen/files.json": Object {
+ "//": "~~ Generated by projen. To modify, edit .projenrc.json and run \\"npx projen\\".",
+ "files": Array [
+ ".gitattributes",
+ ".github/workflows/pull-request-lint.yml",
+ ".gitignore",
+ ".projen/deps.json",
+ ".projen/files.json",
+ ".projen/tasks.json",
+ "setup.py",
+ "version.py",
+ ],
+ },
+ ".projen/tasks.json": Object {
+ "//": "~~ Generated by projen. To modify, edit .projenrc.json and run \\"npx projen\\".",
+ "tasks": Object {
+ "build": Object {
+ "description": "Full release build",
+ "name": "build",
+ "steps": Array [
+ Object {
+ "spawn": "default",
+ },
+ Object {
+ "spawn": "pre-compile",
+ },
+ Object {
+ "spawn": "compile",
+ },
+ Object {
+ "spawn": "post-compile",
+ },
+ Object {
+ "spawn": "test",
+ },
+ Object {
+ "spawn": "package",
+ },
+ ],
+ },
+ "clobber": Object {
+ "condition": "git diff --exit-code > /dev/null",
+ "description": "hard resets to HEAD of origin and cleans the local repo",
+ "env": Object {
+ "BRANCH": "$(git branch --show-current)",
+ },
+ "name": "clobber",
+ "steps": Array [
+ Object {
+ "exec": "git checkout -b scratch",
+ "name": "save current HEAD in \\"scratch\\" branch",
+ },
+ Object {
+ "exec": "git checkout $BRANCH",
+ },
+ Object {
+ "exec": "git fetch origin",
+ "name": "fetch latest changes from origin",
+ },
+ Object {
+ "exec": "git reset --hard origin/$BRANCH",
+ "name": "hard reset to origin commit",
+ },
+ Object {
+ "exec": "git clean -fdx",
+ "name": "clean all untracked files",
+ },
+ Object {
+ "say": "ready to rock! (unpushed commits are under the \\"scratch\\" branch)",
+ },
+ ],
+ },
+ "compile": Object {
+ "description": "Only compile",
+ "name": "compile",
+ },
+ "default": Object {
+ "description": "Synthesize project files",
+ "env": Object {
+ "FILENAME": ".projenrc.json",
+ },
+ "name": "default",
+ "steps": Array [
+ Object {
+ "builtin": "run-projenrc-json",
+ },
+ ],
+ },
+ "eject": Object {
+ "description": "Remove projen from the project",
+ "env": Object {
+ "PROJEN_EJECTING": "true",
+ },
+ "name": "eject",
+ "steps": Array [
+ Object {
+ "spawn": "default",
+ },
+ ],
+ },
+ "package": Object {
+ "description": "Creates the distribution package",
+ "name": "package",
+ },
+ "post-compile": Object {
+ "description": "Runs after successful compilation",
+ "name": "post-compile",
+ },
+ "pre-compile": Object {
+ "description": "Prepare the project for compilation",
+ "name": "pre-compile",
+ },
+ "test": Object {
+ "description": "Run tests",
+ "name": "test",
+ },
+ },
+ },
+ "README.md": "# TestPlugin
+
+Template for an OVOS PHAL plugin.
+
+\`\`\`python
+self.bus.on(\\"mycroft.ready\\", self.on_mycroft_ready)
+\`\`\`
+
+## Credits
+
+authorName (@githubUsername)
+",
+ "requirements.txt": "ovos-utils
+ovos-bus-client
+ovos-workshop
+ovos-plugin-manager
+# Your requirements here
+",
+ "setup.py": "#!/usr/bin/env python3
+from setuptools import setup
+from os import walk, path
+
+BASEDIR = path.abspath(path.dirname(__file__))
+URL = \\"TODO: Add 'repositoryUrl' to .projenrc.json and run pj\\"
+plugin_CLAZZ = \\"TestPlugin\\" # needs to match __init__.py class name
+PYPI_NAME = \\"test-plugin\\" # pip install PYPI_NAME
+
+# below derived from github url to ensure standard plugin_id
+plugin_AUTHOR, plugin_NAME = URL.split(\\".com/\\")[-1].split(\\"/\\")
+plugin_PKG = plugin_NAME.lower().replace(\\"-\\", \\"_\\")
+PLUGIN_ENTRY_POINT = f\\"{plugin_NAME.lower()}.{plugin_AUTHOR.lower()}={plugin_PKG}:{plugin_CLAZZ}\\"
+# plugin_id=package_name:pluginClass
+BASE_PATH = BASE_PATH = path.abspath(path.join(path.dirname(__file__), \\"src\\"))
+
+
+def get_version():
+ \\"\\"\\"Find the version of the package\\"\\"\\"
+ version = None
+ version_file = path.join(BASE_PATH, \\"version.py\\")
+ major, minor, build, alpha = (None, None, None, None)
+ with open(version_file) as f:
+ for line in f:
+ if \\"VERSION_MAJOR\\" in line:
+ major = line.split(\\"=\\")[1].strip()
+ elif \\"VERSION_MINOR\\" in line:
+ minor = line.split(\\"=\\")[1].strip()
+ elif \\"VERSION_BUILD\\" in line:
+ build = line.split(\\"=\\")[1].strip()
+ elif \\"VERSION_ALPHA\\" in line:
+ alpha = line.split(\\"=\\")[1].strip()
+
+ if (major and minor and build and alpha) or \\"# END_VERSION_BLOCK\\" in line:
+ break
+ version = f\\"{major}.{minor}.{build}\\"
+ if alpha and int(alpha) > 0:
+ version += f\\"a{alpha}\\"
+ return version
+
+
+def get_requirements(requirements_filename: str):
+ requirements_file = path.join(path.dirname(__file__), requirements_filename)
+ with open(requirements_file, \\"r\\", encoding=\\"utf-8\\") as r:
+ requirements = r.readlines()
+ requirements = [r.strip() for r in requirements if r.strip() and not r.strip().startswith(\\"#\\")]
+ return requirements
+
+
+def find_resource_files():
+ resource_base_dirs = (\\"locale\\", \\"intents\\", \\"dialog\\", \\"vocab\\", \\"regex\\", \\"ui\\")
+ package_data = [\\"*.json\\"]
+ for res in resource_base_dirs:
+ if path.isdir(path.join(BASE_PATH, res)):
+ for directory, _, files in walk(path.join(BASE_PATH, res)):
+ if files:
+ package_data.append(path.join(directory.replace(BASE_PATH, \\"\\").lstrip(\\"/\\"), \\"*\\"))
+ return package_data
+
+
+with open(\\"README.md\\", \\"r\\") as f:
+ long_description = f.read()
+
+setup(
+ name=PYPI_NAME,
+ version=get_version(),
+ description=\\"\\",
+ long_description=long_description,
+ long_description_content_type=\\"text/markdown\\",
+ url=URL,
+ author=\\"TODO: Add 'author' to .projenrc.json and run pj\\",
+ author_email=\\"TODO: Add 'authorAddress' to .projenrc.json and run pj\\",
+ license=\\"# TODO: Add 'license' to .projenrc.json and run pj\\",
+ package_dir={plugin_PKG: \\"src\\"},
+ package_data={plugin_PKG: find_resource_files()},
+ packages=[plugin_PKG],
+ include_package_data=True,
+ install_requires=get_requirements(\\"requirements.txt\\"),
+ keywords=\\"ovos plugin voice assistant\\",
+ entry_points={ovos.plugin.phal: PLUGIN_ENTRY_POINT},
+)
+",
+ "src/__init__.py": "from ovos_bus_client import Message
+from ovos_plugin_manager.phal import PHALPlugin
+
+
+class HelloWorldPlugin(PHALPlugin):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.bus.on(\\"mycroft.ready\\", self.on_mycroft_ready)
+
+ @property
+ def my_setting(self):
+ \\"\\"\\"Dynamically get the my_setting from the config file(s).
+ Example:
+ {
+ \\"PHAL\\": {
+ \\"ovos-phal-plugin-helloworld\\": {
+ \\"my_setting\\": \\"my_value\\"
+ }
+ }
+ }
+ If it doesn't exist, return the default value.
+ \\"\\"\\"
+ return self.config.get(\\"my_setting\\", \\"default_value\\")
+
+ def on_mycroft_ready(self, message: Message):
+ \\"\\"\\"Take action when OVOS is ready.\\"\\"\\"
+ self.log.info(\\"OVOS reported ready, now I can do something!\\")
+ # Implement something here
+",
+ "src/version.py": "VERSION_MAJOR = 0
+VERSION_MINOR = 0
+VERSION_BUILD = 1
+VERSION_ALPHA = 0",
+ "version.py": "VERSION_MAJOR = 0
+VERSION_MINOR = 0
+VERSION_BUILD = 1
+VERSION_ALPHA = 0",
+}
+`;